跳到主要内容

33 篇关于“工程”的文章

查看所有标签

React Native 月报 #4

·3 分钟阅读
Mike Grabowski
Mike Grabowski
CTO 兼 Callstack 联合创始人

React Native 月度会议继续进行!以下是各团队的笔记

Callstack

  • React Native EU 已经结束。来自 33 个国家的 300 多名参与者访问了弗罗茨瓦夫。演讲内容可以在 YouTube 上找到
  • 会后我们正在慢慢回到我们的开源计划。值得一提的是,我们正在开发 react-native-opentok 的下一个版本,该版本修复了现有的大部分问题。

GeekyAnts

尝试通过以下方式降低开发人员拥抱 React Native 的门槛

  • React Native EU 上发布了 BuilderX.io。BuilderX 是一款直接使用 JavaScript 文件(目前仅支持 React Native)的设计工具,用于生成美观、可读且可编辑的代码。
  • 推出了 ReactNativeSeed.com,它为您的下一个 React Native 项目提供了一套样板。它提供了各种选项,包括用于数据类型的 TypeScript 和 Flow,以及用于状态管理的 MobX、Redux 和 mobx-state-tree,其堆栈为 CRNA 和纯 React-Native。

Expo

  • 即将发布 SDK 21,它增加了对 react-native 0.48.3 的支持,以及 Expo SDK 中的一系列错误修复/可靠性改进/新功能,包括视频录制、新的启动画面 API、对 react-native-gesture-handler 的支持以及改进的错误处理。
  • 关于 react-native-gesture-handlerSoftware MansionKrzysztof Magiera 继续推动其发展,我们一直在帮助他进行测试并资助他的部分开发时间。将其集成到 SDK21 的 Expo 中将允许人们在 Snack 中轻松使用它,因此我们很高兴看到人们能创造出什么。
  • 关于改进的错误日志/处理——有关日志记录的详细信息(特别是“问题 2”),请参阅此 Expo 内部 PR 的要点,以及有关处理导入 npm 标准库模块失败尝试的更改,请参阅此提交。以这种方式改进 React Native 上游的错误消息有很多机会,我们将继续在上游 PR 上进行后续工作。社区也能参与进来就太好了。
  • native.directory 持续增长,您可以从 GitHub 仓库添加您的项目。
  • 参加北美各地的黑客马拉松,包括 PennAppsHack The NorthHackMIT,以及即将到来的 MHacks

Facebook

  • 正在努力改进 Android 上的 <Text><TextInput> 组件。(<TextInput> 的原生自动增长;深度嵌套的 <Text> 组件布局问题;更好的代码结构;性能优化)。
  • 我们仍在寻找愿意协助分类问题和拉取请求的额外贡献者。

Microsoft

  • 发布了 CodePush 的代码签名功能。React Native 开发者现在可以在 CodePush 中签署他们的应用程序包。公告可以在这里找到。
  • 正在努力完成 CodePush 与 Mobile Center 的集成。同时也在考虑测试/崩溃集成。

下一次会议

下一次会议定于 2017 年 10 月 10 日星期三举行。由于这只是我们的第四次会议,我们想知道这些笔记对 React Native 社区有什么益处。如果您对我们如何改进会议成果有任何建议,请随时在 Twitter 上给我发消息。

React Native 月报 #3

·阅读时长5分钟
Mike Grabowski
Mike Grabowski
CTO 兼 Callstack 联合创始人

React Native 月度会议仍在继续!本月的会议稍短,因为我们的大多数团队都在忙于发布。下个月,我们将在波兰弗罗茨瓦夫参加 React Native EU 会议。请务必购买门票,我们到时候会在现场见到您!同时,让我们看看我们的团队都在忙些什么。

团队

本次第三次会议,有 5 个团队加入了我们

备忘

以下是各团队的备注

Callstack

  • 最近开源了 react-native-material-palette。它从图像中提取主要颜色,帮助您创建具有视觉吸引力的应用程序。目前它只支持 Android,但我们正在考虑未来添加对 iOS 的支持。
  • 我们已将 HMR 支持和许多其他很酷的东西加入到 haul 中!查看最新版本。
  • React Native 欧洲大会 2017 即将到来!下个月将是 React Native 和波兰的天下!请务必在这里抢购最后几张票。

Expo

  • 发布了在 Snack 上安装 npm 包的支持。通常的 Expo 限制适用——包不能依赖于 Expo 中尚未包含的自定义原生 API。我们还在努力支持 Snack 中的多个文件和上传资源。Satyajit 将在 React Native Europe 上谈论 Snack。
  • 发布了 SDK20,支持相机、支付、安全存储、磁力计、文件系统下载的暂停/恢复,以及改进的启动/加载屏幕。
  • 继续与 Krzysztof 合作开发 react-native-gesture-handler。请试用一下,使用 PanResponder 或原生手势识别器重新构建您以前构建的一些手势,并让我们知道您遇到了哪些问题。
  • 正在试验 JSC 调试协议,并处理 Canny 上的一堆功能请求。

Facebook

  • 上个月我们讨论了 GitHub 问题跟踪器的管理,以及我们将尝试改进以解决项目的可维护性问题。
  • 目前,开放问题的数量稳定在 600 个左右,并且似乎会在一段时间内保持这种状态。在过去的一个月里,我们因缺乏活动(定义为过去 60 天内没有评论)而关闭了 690 个问题。在这 690 个问题中,有 58 个因各种原因重新打开(维护人员承诺提供修复,或者贡献者提出了充分的理由来保持问题开放)。
  • 我们计划在可预见的未来继续自动关闭过时问题。我们希望达到这样的状态:跟踪器中打开的每一个有影响力的问题都会得到处理,但我们还没有做到。我们需要维护人员提供一切帮助来分类问题,并确保我们不会错过引入回归或破坏性更改的问题,特别是那些影响新创建项目的问题。有兴趣提供帮助的人可以使用 Facebook GitHub Bot 来分类问题和拉取请求。新的维护人员指南包含更多关于分类和使用 GitHub Bot 的信息。请将您自己添加到 问题工作组,并鼓励其他活跃社区成员也这样做!

Microsoft

  • 新的 Skype 应用基于 React Native 构建,以尽可能多地在平台之间共享代码。基于 React Native 的 Skype 应用目前可在 Android 和 iOS 应用商店中获取。
  • 在 React Native 上构建 Skype 应用程序时,我们向 React Native 发送拉取请求,以解决我们遇到的错误和缺失功能。到目前为止,我们已合并了大约 70 个拉取请求
  • React Native 使我们能够从相同的代码库为 Android 和 iOS Skype 应用程序提供支持。我们还希望使用该代码库为 Skype 网络应用程序提供支持。为了帮助我们实现这一目标,我们构建并开源了一个基于 React/React Native 的薄层,称为 ReactXP。ReactXP 提供了一组跨平台组件,在针对 iOS/Android 时映射到 React Native,在针对 Web 时映射到 react-dom。ReactXP 的目标与另一个名为 React Native for Web 的开源库类似。在 ReactXP FAQ 中简要描述了这些库方法的不同之处。

Shoutem

  • 我们正在继续努力改进和简化使用 Shoutem 构建应用程序时的开发人员体验。
  • 开始将我们所有的应用程序迁移到 react-navigation,但我们最终推迟了这一进程,直到更稳定的版本发布,或者其中一个原生导航解决方案变得稳定。
  • 将我们所有的 扩展 和我们大多数开源库(动画主题UI)更新到 React Native 0.47.1。

下一次会议

下一次会议定于 2017 年 9 月 13 日星期三举行。由于这只是我们的第三次会议,我们想知道这些笔记如何有益于 React Native 社区。如果您对我们应该如何改进会议成果有任何建议,请随时在 Twitter 上联系我。

市场中的 React Native 性能

·6 分钟阅读
Facebook 软件工程师

React Native 被广泛应用于 Facebook 家族的多个应用程序的多个位置,包括主 Facebook 应用程序中的顶级选项卡。本文的重点是一个高度可见的产品,Marketplace。它在十几个国家/地区可用,用户可以通过它发现其他用户提供的产品和服务。

在 2017 年上半年,通过 Relay 团队、Marketplace 团队、移动 JS 平台团队和 React Native 团队的共同努力,我们成功将 Android 2010-11 年份设备上 Marketplace 的交互时间 (TTI) 缩短了一半。Facebook 历来将这些设备视为低端 Android 设备,它们的 TTI 在所有平台或设备类型中都是最慢的。

典型的 React Native 启动过程如下所示:

免责声明:比例不具代表性,会因 React Native 的配置和使用方式而异。

我们首先初始化 React Native 核心(即“Bridge”),然后运行特定于产品的 JavaScript,它决定了 React Native 将在原生处理时间中渲染哪些原生视图。

一种不同的方法

我们早期犯的一个错误是让 Systrace 和 CTScan 来驱动我们的性能优化工作。这些工具在 2016 年帮助我们发现了许多唾手可得的成果,但我们发现 Systrace 和 CTScan 都不能代表生产环境,也无法模拟实际情况。时间分配的比例通常不正确,有时甚至完全偏离。在极端情况下,我们预期只需几毫秒的事情,实际上却需要数百或数千毫秒。尽管如此,CTScan 仍然有用,我们发现它能在三分之一的回归问题进入生产环境之前捕获它们。

在 Android 上,我们将这些工具的缺点归因于以下事实:1) React Native 是一个多线程框架,2) Marketplace 与 Newsfeed 和其他顶级选项卡等众多复杂视图共存,3) 计算时间差异巨大。因此,本半年,我们几乎所有的决策和优先级都由生产测量和细分来驱动。

深入生产环境检测

表面上,生产环境检测可能听起来很简单,但事实证明这是一个相当复杂的过程。它经历了多个迭代周期,每个周期持续 2-3 周;由于将提交合并到主分支、将应用程序推送到 Play 商店以及收集足够的生产样本以确保我们工作的准确性存在延迟。每个迭代周期都涉及发现我们的细分是否准确,它们是否具有正确的粒度,以及它们是否正确地加总到整个时间跨度。我们不能依赖 alpha 和 beta 版本,因为它们不代表一般用户群体。本质上,我们非常细致地构建了一个基于数百万样本聚合的非常准确的生产跟踪。

我们之所以一丝不苟地验证细分中的每一毫秒都正确地加总到它们的父指标,原因之一是我们很早就意识到我们的检测存在空白。事实证明,我们最初的细分并未考虑到线程跳转导致的停顿。线程跳转本身并不昂贵,但跳转到已经在忙碌的线程却非常昂贵。我们最终通过在正确的时间点添加 Thread.sleep() 调用来在本地重现这些阻塞,并通过以下方式成功修复了它们:

  1. 移除对 AsyncTask 的依赖,
  2. 撤销在 UI 线程上强制初始化 ReactContext 和 NativeModules,以及
  3. 消除初始化时测量 ReactRootView 的依赖。

综合来看,消除这些线程阻塞问题将启动时间缩短了25%以上。

生产指标也挑战了我们之前的一些假设。例如,我们过去在启动路径上预加载许多 JavaScript 模块,假设将模块放在一个包中会降低它们的初始化成本。然而,预加载和共置这些模块的成本远远超过了收益。通过重新配置我们的内联 require 黑名单并从启动路径中移除 JavaScript 模块,我们能够避免加载不必要的模块,例如 Relay Classic(当只需要 Relay Modern 时)。如今,我们的 RUN_JS_BUNDLE 细分速度提高了 75% 以上。

我们还通过调查特定产品原生模块发现了胜利。例如,通过惰性注入原生模块的依赖项,我们将该原生模块的成本降低了 98%。通过消除 Marketplace 启动与其他产品之间的竞争,我们相应地缩短了启动时间。

最棒的是,其中许多改进都广泛适用于所有使用 React Native 构建的屏幕。

结论

人们通常认为 React Native 启动性能问题是由于 JavaScript 运行缓慢或网络时间过长造成的。虽然加快 JavaScript 等会使 TTI 降低一个不小的总和,但这些因素对 TTI 的贡献百分比远低于之前的估计。

到目前为止的教训是:衡量、衡量、再衡量!有些胜利来自于将运行时成本转移到构建时,例如 Relay Modern 和 Lazy NativeModules。其他的胜利则来自于通过更智能地并行化代码或移除死代码来避免不必要的工作。还有一些胜利来自于 React Native 的大型架构更改,例如清理线程阻塞。性能没有一劳永逸的解决方案,长期的性能提升将来自于渐进式的检测和改进。不要让认知偏差影响你的决策。相反,仔细收集和解释生产数据以指导未来的工作。

未来计划

从长远来看,我们希望 Marketplace 的 TTI 能与使用原生技术构建的类似产品相媲美,并且通常情况下,React Native 的性能能够与原生性能持平。此外,尽管本半年我们大幅将桥接启动成本降低了约 80%,但我们计划通过 Prepack 等项目以及更多的构建时处理,将 React Native 桥接的成本降至接近于零。

React Native 月报 #2

·阅读时长 9 分钟
Tomislav Tenodi
Shoutem 产品经理

React Native 每月例会仍在继续!本次会议,我们邀请到了 Infinite Red,他们是 Chain React,React Native 大会背后的杰出团队。由于在座大多数人都在 Chain React 大会上发表了演讲,我们将会议推迟了一周。大会的演讲视频已发布到线上,我鼓励大家去观看。那么,让我们看看我们的团队都在忙些什么。

团队

第二次会议,共有9个团队加入我们

备忘

以下是各团队的备注

Airbnb

Callstack

  • Mike Grabowski 一如既往地管理着 React Native 的每月发布,包括推出了一些测试版。特别是,正在努力将 v0.43.5 版本发布到 npm,因为它将解除 Windows 用户的阻止!
  • Haul 正在缓慢但持续地推进。有一个添加了 HMR 的拉取请求,其他改进也已发布。最近有几家行业领导者采用了它。可能计划在该领域开始全职有偿工作。
  • 本月,来自 Jest 团队的 Michał Pierzchała 加入了 Callstack。他将帮助维护 Haul,并可能参与 Metro BundlerJest 的工作。
  • Satyajit Sahoo 现在和我们在一起了,太棒了!
  • 我们的开源部门即将推出一系列酷炫的东西。特别是,正在努力将 Material Palette API 引入 React Native。计划最终发布我们的原生 iOS 套件,旨在提供 1:1 的原生组件外观和感觉。

Expo

  • 最近推出了 Native Directory,旨在帮助发现和评估 React Native 生态系统中的库。问题在于:库很多,测试困难,需要手动应用启发式方法,而且哪些是最好用的并不立即显而易见。也很难知道某些东西是否与 CRNA/Expo 兼容。所以 Native Directory 试图解决这些问题。查看一下并将你的库添加到其中。库列表在这里。这只是我们的第一步,我们希望它由社区拥有和运营,而不仅仅是 Expo 团队。所以如果你认为这有价值并想让它变得更好,请积极参与!
  • Snack 中使用 Expo SDK 19 添加了对安装 npm 包的初步支持。如果你遇到任何问题,请告诉我们,我们仍在解决一些 bug。结合 Native Directory,这应该可以轻松测试只包含 JS 依赖项或包含在 Expo SDK 中的依赖项的库。试试看
  • 发布了 Expo SDK19,其中包含全面的改进,我们现在正在使用更新的 Android JSC
  • 正在与 Alexander Kotliarskyi 一起撰写一份文档指南,其中包含有关如何改善应用用户体验的提示列表。请加入并添加到列表中或帮助撰写其中一些内容!
  • 继续致力于:音频/视频、相机、手势(与 Software Mansion 合作,react-native-gesture-handler)、GL 相机集成,并希望在 SDK20(8 月)首次推出其中一些功能,并在那时对其他功能进行重大改进。我们刚开始在 Expo 客户端中构建后台工作(地理定位、音频、处理通知等)的基础设施。
  • Adam Miskiewicz 在模仿 UINavigationControllerreact-navigation 中的过渡方面取得了不错的进展。查看 他的推文 中的早期版本——很快就会发布。还可以查看他上游MaskedViewIOS。如果你有能力和意愿为 Android 实现 MaskedView,那将非常棒!

Facebook

  • Facebook 正在内部探索将原生 ComponentKitLitho 组件嵌入到 React Native 中的可能性。
  • 非常欢迎对 React Native 的贡献!如果你想知道如何贡献,“如何贡献”指南描述了我们的开发流程并列出了发送你的第一个拉取请求的步骤。还有其他不需编写代码的贡献方式,例如分类问题或更新文档。
    • 截至撰写本文时,React Native 有 635开放问题249开放拉取请求。这对我们的维护者来说是巨大的负担,当内部修复问题时,很难确保相关任务得到更新。
    • 我们不确定在保持社区满意的情况下处理此问题的最佳方法是什么。一些(但不是全部!)选项包括关闭陈旧问题、授予更多人管理问题的权限,以及自动关闭不符合问题模板的问题。我们撰写了“维护者期望”指南,以设定期望并避免意外。如果您对我们如何改善维护者的体验,并确保提出问题和拉取请求的人感受到被倾听和重视有任何想法,请告诉我们!

GeekyAnts

  • 我们在 Chain React 上演示了与 React Native 文件协同工作的设计工具。许多与会者报名了候补名单。
  • 我们还在研究其他跨平台解决方案,如 Google Flutter(即将进行重大比较)、Kotlin NativeApache Weex,以了解它们的架构差异,并从中学习如何改进 React Native 的整体性能。
  • 我们的大部分应用程序都切换到了 react-navigation,这改善了整体性能。
  • 此外,还发布了 NativeBase Market - 一个面向(并由)开发者的 React Native 组件和应用程序市场。

Infinite Red

Microsoft

  • CodePush 现已集成到 Mobile Center 中。现有用户的工作流程将保持不变。
    • 一些人报告了重复应用程序的问题——他们已经在 Mobile Center 上有一个应用程序。我们正在努力解决这些问题,但是如果您有两个应用程序,请告诉我们,我们可以为您合并它们。
  • Mobile Center 现在支持 CodePush 的推送通知。我们还展示了如何将通知和 CodePush 结合起来用于 A/B 测试应用程序——这是 React Native 架构独有的功能。
  • VS Code 在 ReactNative 上有一个已知的调试问题——扩展的下一个版本将在几天内修复此问题。
  • 由于微软内部还有许多其他团队也在从事 React Native 的工作,我们将在下次会议上努力争取所有团队的更好代表。

Shoutem

  • 完成了在 Shoutem 上简化 React Native 开发的过程。在 Shoutem 上开发应用程序时,可以使用所有标准的 react-native 命令。
  • 我们做了很多工作,试图找出如何在 React Native 上最好地进行性能分析。大部分文档已经过时,我们将尽力在官方文档上创建拉取请求,或者至少在博客文章中写下我们的一些结论。
  • 我们正在将导航解决方案切换到 react-navigation,因此我们可能很快会有一些反馈。
  • 我们在工具包中发布了一个新的 HTML 组件,它将原始 HTML 转换为 React Native 组件树。

Wix

  • 我们开始着手为 Metro Bundler 提交一个拉取请求,该请求将支持 react-native-repackager 的功能。我们已经更新了 react-native-repackager 以支持 RN 44(我们正在生产环境中使用)。我们正在将其用于 detox 的模拟基础设施。
  • 在过去三周里,我们一直在使用 detox 测试 Wix 应用。这是一个了不起的学习经验,了解如何在如此规模的应用(超过 40 名工程师)中减少手动 QA。因此,我们解决了 detox 的几个问题,新版本刚刚发布。我很高兴地报告,我们正在履行“零不稳定性政策”,到目前为止测试一直稳定通过。
  • Detox for Android 进展顺利。我们得到了社区的大力帮助。我们预计在大约两周内推出初始版本。
  • DetoxInstruments,我们的性能测试工具,正在变得比我们最初设想的要大一些。我们现在计划将其转换为一个独立的工具,它将不会与 detox 紧密耦合。它将允许全面调查 iOS 应用程序的性能。它还将与 detox 集成,以便我们可以对性能指标运行自动化测试。

下一次会议

下一次会议定于 2017 年 8 月 16 日举行。由于这只是我们的第二次会议,我们想知道这些笔记对 React Native 社区有何益处。如果您对我们如何改进会议成果有任何建议,请随时在 Twitter 上联系我

React Native 月报 #1

·6 分钟阅读
Tomislav Tenodi
Shoutem 产品经理

Shoutem,我们很幸运地从 React Native 的早期阶段就开始使用它。我们决定从第一天起就成为这个优秀社区的一部分。很快,我们意识到要跟上社区发展和改进的速度几乎是不可能的。这就是为什么我们决定组织一个每月会议,让所有主要的 React Native 贡献者可以简要介绍他们的工作和计划。

每月会议

我们在 2017 年 6 月 14 日举行了第一次月度会议。React Native 每月会议的使命简单明了:改善 React Native 社区。展示团队的努力有助于团队之间进行线下协作。

团队

在第一次会议上,有8个团队加入了我们

我们希望有更多的核心贡献者加入接下来的会议!

备忘

由于团队的计划可能会引起更广泛受众的兴趣,我们将在这里,在 React Native 博客上分享它们。所以,它们来了

Airbnb

  • 计划为 ViewAccessibilityInfo 原生模块添加一些 A11y(可访问性)API。
  • 将调查在 Android 上为原生模块添加一些 API,以允许指定它们运行的线程。
  • 一直在调查潜在的初始化性能改进。
  • 一直在调查一些更复杂的打包策略,以便在“unbundle”之上使用。

Callstack

  • 正在研究通过使用 Detox 进行 E2E 测试来改进发布流程。拉取请求应该很快就会合并。
  • 他们一直在开发的 Blob 拉取请求已合并,后续拉取请求即将到来。
  • 在内部项目中增加 Haul 的采用,以观察其与 Metro Bundler 相比的性能。与 webpack 团队合作,以提高多线程性能。
  • 在内部,他们已经建立了一个更好的基础设施来管理开源项目。计划在未来几周内推出更多内容。
  • React Native Europe 会议即将举行,目前还没有特别有趣的内容,但欢迎大家参加!
  • 暂时退出了 react-navigation 一段时间,以调查替代方案(特别是原生导航)。

Expo

  • 正在努力使 Snack 中可以安装 npm 模块,这对于库来说,在文档中添加示例将非常有用。
  • KrzysztofSoftware Mansion 的其他人合作,进行 Android 上的 JSC 更新和手势处理库的开发。
  • Adam Miskiewicz 正在将他的重心转向 react-navigation
  • Create React Native App 已收录在文档的入门指南中。Expo 希望鼓励库作者明确说明他们的库是否适用于 CRNA,如果适用,请解释如何进行设置。

Facebook

  • React Native 的打包器现在是 Metro Bundler,位于一个独立的仓库中。Metro Bundler 团队在伦敦很高兴能满足社区的需求,改进模块化以支持 React Native 之外的更多用例,并提高对问题和 PR 的响应速度。
  • 在接下来的几个月里,React Native 团队将致力于完善原始组件的 API。预计在布局怪癖、可访问性和流程类型方面会有改进。
  • React Native 团队还计划今年通过重构来改进核心模块化,以完全支持 Windows 和 macOS 等第三方平台。

GeekyAnts

  • 团队正在开发一款 UI/UX 设计应用程序(代号:Builder),它直接处理 .js 文件。目前,它只支持 React Native。它类似于 Adobe XD 和 Sketch。
  • 团队正在努力工作,以便您可以在编辑器中加载现有的 React Native 应用程序,进行更改(以设计师的视角进行视觉更改),并将更改直接保存到 JS 文件中。
  • 大家正在努力弥合设计师和开发者之间的差距,并将他们带到同一个代码仓库中。
  • 此外,NativeBase 最近达到了 5,000 个 GitHub 星。

Microsoft

  • CodePush 现已集成到 Mobile Center 中。这是提供与分发、分析和其他服务更集成体验的第一步。请在此处查看他们的公告。
  • VS Code 在调试方面存在一个 bug,他们正在努力修复,并将发布新的构建版本。
  • 正在研究 Detox 进行集成测试,并研究 JSC Context 以获取变量和崩溃报告。

Shoutem

  • 使用 React Native 社区的工具,让 Shoutem 应用的开发变得更轻松。您将能够使用所有 React Native 命令来运行在 Shoutem 上创建的应用。
  • 正在研究 React Native 的性能分析工具。他们在设置时遇到了很多问题,并将撰写他们在此过程中发现的一些见解。
  • Shoutem 正在努力使 React Native 与现有原生应用程序的集成变得更容易。他们将记录公司内部开发的概念,以获取社区的反馈。

Wix

  • Wix 内部正在努力采用 Detox,以将 Wix 应用的很大一部分转变为“零手动 QA”。因此,Detox 正在被数十位开发者在生产环境中大量使用,并迅速成熟。
  • 正在努力为 Metro Bundler 添加支持,以在构建期间覆盖任何文件扩展名。它将支持任何自定义扩展名,如“e2e”或“detox”,而不仅仅是“ios”和“android”。计划将其用于 E2E 模拟。已经有一个名为 react-native-repackager 的库,现在正在处理 PR。
  • 正在研究性能测试自动化。这是一个名为 DetoxInstruments 的新仓库。您可以查看一下,它正在开源开发中。
  • 与 KPN 的一位贡献者合作,开发适用于 Android 的 Detox 并支持真实设备。
  • 正在考虑将“Detox 作为一个平台”,以允许构建其他需要自动化模拟器/设备的工具。一个例子是 Storybook for React Native 或 Ram 的集成测试想法。

下一次会议

会议将每四周举行一次。下一次会议定于 2017 年 7 月 12 日举行。由于我们刚开始召开这个会议,我们想知道这些笔记如何有益于 React Native 社区。如果您对我们在接下来的会议中应该涵盖的内容,或者我们应该如何改进会议的输出有任何建议,请随时在 Twitter 上给我发消息

React Native 中更好的列表视图

·6 分钟阅读

在社区群组中发布预告后,许多人已经开始试用我们新的列表组件,但我们今天才正式宣布它们!不再有 ListViewDataSource,不再有陈旧的行、被忽略的 bug 或过度的内存消耗——随着最新的 React Native 2017 年 3 月发布候选版本 (0.43-rc.1) 的发布,您可以从新的组件套件中选择最适合您用例的组件,它们都具有出色的性能和开箱即用的功能集。

<FlatList>

这是用于简单、高性能列表的主力组件。提供一个数据数组和一个renderItem函数,就可以开始使用了。

<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>

<SectionList>

如果您想渲染一组数据,这些数据被分成逻辑部分,可能带有部分标题(例如,按字母顺序排列的地址簿),并且可能具有异构数据和渲染(例如,一个个人资料视图,带有一些按钮,然后是一个编辑器,然后是一个照片网格,然后是一个朋友网格,最后是故事列表),这就是您的最佳选择。

<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>

<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>

<VirtualizedList>

更灵活的 API 的幕后实现。如果您的数据不是纯数组(例如,一个不可变列表),则特别方便。

特性

列表在许多情况下使用,因此我们为新组件提供了许多功能,以处理大多数开箱即用的用例。

  • 滚动加载 (onEndReached)。
  • 下拉刷新 (onRefresh / refreshing)。
  • 可配置的可见性 (VPV) 回调 (onViewableItemsChanged / viewabilityConfig)。
  • 水平模式 (horizontal)。
  • 智能项目和节分隔符。
  • 多列支持 (numColumns)
  • scrollToEndscrollToIndexscrollToItem
  • 更好的 Flow 类型。

一些注意事项

  • 当内容滚动出渲染窗口时,项目子树的内部状态不会保留。确保所有数据都捕获在项目数据或外部存储中,如 Flux、Redux 或 Relay。

  • 这些组件基于 PureComponent,这意味着如果 props 保持浅层相等,它们将不会重新渲染。确保 renderItem 函数直接依赖的所有内容都作为在更新后不为 === 的 prop 传递,否则您的 UI 可能不会随着更改而更新。这包括 data prop 和父组件状态。例如

    <FlatList
    data={this.state.data}
    renderItem={({item}) => (
    <MyItem
    item={item}
    onPress={() =>
    this.setState(oldState => ({
    selected: {
    // New instance breaks `===`
    ...oldState.selected, // copy old data
    [item.key]: !oldState.selected[item.key], // toggle
    },
    }))
    }
    selected={
    !!this.state.selected[item.key] // renderItem depends on state
    }
    />
    )}
    selected={
    // Can be any prop that doesn't collide with existing props
    this.state.selected // A change to selected should re-render FlatList
    }
    />
  • 为了限制内存和实现流畅滚动,内容会在屏幕外异步渲染。这意味着滚动速度可能快于填充速度,并短暂地看到空白内容。这是一个可以根据每个应用程序的需求进行调整的权衡,我们正在幕后努力改进它。

  • 默认情况下,这些新列表会在每个项目上查找一个key prop,并将其用作 React 键。或者,您可以提供一个自定义的keyExtractor prop。

性能

除了简化 API,新的列表组件还具有显著的性能增强,其中最主要的是对于任意数量的行,内存使用几乎恒定。这是通过“虚拟化”渲染窗口之外的元素来实现的,即从组件层次结构中完全卸载它们并回收 React 组件的 JS 内存,以及影子树和 UI 视图的本机内存。这有一个缺点,即内部组件状态将不会被保留,因此请确保您在组件本身之外跟踪任何重要的状态,例如在 Relay、Redux 或 Flux 存储中。

限制渲染窗口还可以减少 React 和原生平台需要完成的工作量,例如视图遍历。即使您正在渲染一百万个元素中的最后一个,使用这些新列表,也无需遍历所有这些元素即可渲染。您甚至可以使用 scrollToIndex 跳转到中间而不会进行过度的渲染。

我们还对调度进行了一些改进,这应该有助于提高应用程序的响应能力。渲染窗口边缘的项很少渲染,并且在任何活动手势、动画或其他交互完成后以较低的优先级渲染。

高级用法

ListView 不同,渲染窗口中的所有项在任何 props 更改时都会重新渲染。通常这没问题,因为窗口化将项的数量减少到常数,但如果您的项比较复杂,您应该确保遵循 React 性能的最佳实践,并在您的组件中使用 React.PureComponent 和/或 shouldComponentUpdate 以限制递归子树的重新渲染。

如果您可以在不渲染行的情况下计算行的高度,您可以通过提供 getItemLayout prop 来改善用户体验。这使得使用 scrollToIndex 等滚动到特定项时更加平滑,并且会改善滚动指示器 UI,因为可以在不渲染内容的情况下确定内容的高度。

如果您有替代数据类型,例如不可变列表,则<VirtualizedList>是最佳选择。它接受一个getItem prop,允许您返回任何给定索引的项目数据,并且具有更宽松的 Flow 类型。

如果您有不寻常的用例,还可以调整许多参数。例如,您可以使用 windowSize 来权衡内存使用和用户体验,使用 maxToRenderPerBatch 来调整填充率和响应性,使用 onEndReachedThreshold 来控制何时发生滚动加载等等。

未来工作

  • 现有界面的迁移(最终废弃ListView)。
  • 根据我们的需求/意见增加更多功能(请告诉我们!)。
  • 粘性节标题支持。
  • 更多性能优化。
  • 支持带状态的功能项目组件。

idx:存在函数

·阅读时长2分钟
Timothy Yung
Facebook 工程经理

在 Facebook,我们经常需要访问通过 GraphQL 获取的数据结构中深度嵌套的值。在访问这些深度嵌套的值时,一个或多个中间字段常常是可为空的。这些中间字段为空的原因有很多,从隐私检查失败到仅仅是因为 null 是表示非致命错误最灵活的方式。

不幸的是,访问这些深度嵌套的值目前既繁琐又冗长。

props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends;

有一个 ECMAScript 提案旨在引入存在运算符,这将使这种情况方便得多。但在该提案最终确定之前,我们希望有一个解决方案能够提高我们的生活质量,保持现有的语言语义,并鼓励 Flow 的类型安全。

我们想出了一个名为 idx 的存在性函数

idx(props, _ => _.user.friends[0].friends);

此代码片段中的调用与上面代码片段中的布尔表达式的行为类似,但重复性大大降低。idx 函数严格接受两个参数

  • 任何值,通常是您要访问嵌套值的对象或数组。
  • 一个函数,它接收第一个参数并访问其上的嵌套值。

理论上,idx 函数将尝试捕获由于访问 null 或 undefined 上的属性而导致的错误。如果捕获到此类错误,它将返回 null 或 undefined。(您可以在 idx.js 中查看如何实现这一点。)

实际上,对每个嵌套属性访问进行 try-catch 是缓慢的,并且区分特定类型的 TypeError 是脆弱的。为了解决这些缺点,我们创建了一个 Babel 插件,将上述 idx 调用转换为以下表达式

props.user == null
? props.user
: props.user.friends == null
? props.user.friends
: props.user.friends[0] == null
? props.user.friends[0]
: props.user.friends[0].friends;

最后,我们为 idx 添加了一个自定义的 Flow 类型声明,允许在第二个参数中进行遍历的类型检查,同时允许对可空属性进行嵌套访问。

该函数、Babel 插件和 Flow 声明现已 在 GitHub 上提供。它们通过安装 idxbabel-plugin-idx npm 包,并将“idx”添加到 .babelrc 文件中的插件列表中来使用。

引入 Create React Native App

·3 分钟阅读
Adam Perry
Expo 软件工程师

今天我们宣布推出 Create React Native App:一个新工具,可以大大简化 React Native 项目的入门!它深受 Create React App 设计的启发,是 FacebookExpo(前身为 Exponent)合作的产物。

许多开发者在安装和配置 React Native 当前的原生构建依赖项时遇到困难,尤其是对于 Android。使用 Create React Native App,无需使用 Xcode 或 Android Studio,您可以使用 Linux 或 Windows 为您的 iOS 设备进行开发。这是通过 Expo 应用程序实现的,它加载并运行用纯 JavaScript 编写的 CRNA 项目,而无需编译任何原生代码。

尝试创建一个新项目(如果已安装 yarn,请替换为合适的 yarn 命令)

$ npm i -g create-react-native-app
$ create-react-native-app my-project
$ cd my-project
$ npm start

这将启动 React Native 打包器并打印一个二维码。在 Expo 应用程序中打开它以加载您的 JavaScript。对 console.log 的调用将转发到您的终端。您可以使用任何标准 React Native API 以及 Expo SDK

原生代码怎么办?

许多 React Native 项目都有需要编译的 Java 或 Objective-C/Swift 依赖项。Expo 应用程序确实包含相机、视频、联系人等 API,并捆绑了流行的库,例如 Airbnb 的 react-native-mapsFacebook 认证。但是,如果您需要 Expo 未捆绑的原生代码依赖项,那么您可能需要为其拥有自己的构建配置。就像 Create React App 一样,CRNA 支持“弹出”。

您可以运行 npm run eject 以获得一个与 react-native init 生成的项目非常相似的项目。届时,您将需要 Xcode 和/或 Android Studio,就像您从 react-native init 开始一样,使用 react-native link 添加库将起作用,并且您将完全控制原生代码编译过程。

有问题?反馈?

Create React Native App 现在已足够稳定,可供一般使用,这意味着我们非常渴望听到您使用它的体验!您可以在 Twitter 上找到我,或在 GitHub 存储库上提出问题。非常欢迎拉取请求!

使用原生驱动动画

·6 分钟阅读
Janic Duplessis
App & Flow 软件工程师

在过去的一年里,我们一直致力于提高使用 Animated 库的动画性能。动画对于创造出色的用户体验至关重要,但也很难做好。我们希望让开发人员能够轻松创建高性能动画,而不必担心他们的某些代码会导致动画卡顿。

这是什么?

Animated API 的设计考虑了一个非常重要的限制,即它是可序列化的。这意味着我们可以在动画开始之前将动画的所有内容发送到原生层,并允许原生代码在 UI 线程上执行动画,而无需在每一帧都经过桥接。这非常有用,因为一旦动画开始,JS 线程就可以被阻塞,动画仍然会流畅运行。实际上,这经常发生,因为用户代码在 JS 线程上运行,并且 React 渲染也可能长时间锁定 JS 线程。

一点历史...

本项目大约在一年前启动,当时 Expo 在 Android 上构建了 li.st 应用。Krzysztof Magiera 受聘在 Android 上构建了最初的实现。最终它运行良好,li.st 成为首个使用 Animated 驱动原生动画的应用。几个月后,Brandon Withrow 在 iOS 上构建了最初的实现。之后,Ryan Gomba 和我致力于添加缺失的功能,例如支持 Animated.event,以及修复我们在生产应用中使用时发现的错误。这确实是一项社区努力,我要感谢所有参与者,以及 Expo 为大部分开发提供赞助。它现在被 React Native 中的 Touchable 组件以及新发布的 React Navigation 库中的导航动画所使用。

它是如何工作的?

首先,让我们看看使用带有 JS 驱动程序的 Animated 动画目前是如何工作的。使用 Animated 时,您声明一个表示要执行的动画的节点图,然后使用驱动程序使用预定义的曲线更新 Animated 值。您还可以通过使用 Animated.event 将 Animated 值连接到 View 的事件来更新它。

以下是动画步骤及其发生位置的分解

  • JS:动画驱动器使用 requestAnimationFrame 在每一帧执行,并根据动画曲线计算出的新值更新它驱动的值。
  • JS:计算中间值并将其传递给附加到 View 的 props 节点。
  • JS:使用 setNativeProps 更新 View
  • JS 到原生桥。
  • 原生:更新 UIViewandroid.View

如您所见,大部分工作都在 JS 线程上进行。如果它被阻塞,动画将跳帧。它还需要在每一帧通过 JS 到原生桥来更新原生视图。

原生驱动程序所做的是将所有这些步骤移至原生。由于 Animated 生成一个动画节点图,因此可以在动画开始时一次性序列化并发送到原生层,从而无需回调到 JS 线程;原生代码可以在每一帧直接在 UI 线程上更新视图。

以下是我们如何序列化动画值和插值节点的示例(不是确切的实现,只是一个示例)。

创建原生值节点,这是将要动画化的值

NativeAnimatedModule.createNode({
id: 1,
type: 'value',
initialValue: 0,
});

创建原生插值节点,这告诉原生驱动程序如何插值一个值

NativeAnimatedModule.createNode({
id: 2,
type: 'interpolation',
inputRange: [0, 10],
outputRange: [10, 0],
extrapolate: 'clamp',
});

创建原生 props 节点,这告诉原生驱动程序它附加到视图的哪个 props

NativeAnimatedModule.createNode({
id: 3,
type: 'props',
properties: ['style.opacity'],
});

连接节点

NativeAnimatedModule.connectNodes(1, 2);
NativeAnimatedModule.connectNodes(2, 3);

将 props 节点连接到视图

NativeAnimatedModule.connectToView(3, ReactNative.findNodeHandle(viewRef));

这样,原生动画模块就拥有了更新原生视图所需的所有信息,而无需转到 JS 计算任何值。

剩下要做的就是实际启动动画,方法是指定我们想要的动画曲线类型以及要更新的动画值。通过在 JS 中提前计算动画的每一帧,也可以简化时序动画,从而使原生实现更小。

NativeAnimatedModule.startAnimation({
type: 'timing',
frames: [0, 0.1, 0.2, 0.4, 0.65, ...],
animatedValueId: 1,
});

现在是动画运行时发生的事情的分解

  • 原生:原生动画驱动程序使用 CADisplayLinkandroid.view.Choreographer 在每一帧执行,并根据动画曲线计算出的新值更新它驱动的值。
  • 原生:计算中间值并将其传递给附加到原生视图的 props 节点。
  • 原生:更新 UIViewandroid.View

如您所见,不再有 JS 线程和桥接,这意味着更快的动画!🎉🎉

我如何在我的应用程序中使用它?

对于普通动画,答案很简单,只需在启动动画时在动画配置中添加 useNativeDriver: true 即可。

之前

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
}).start();

之后

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // <-- Add this
}).start();

动画值只与一个驱动程序兼容,因此如果您在某个值上启动动画时使用原生驱动程序,请确保该值上的每个动画也使用原生驱动程序。

它也适用于 Animated.event,这非常有用,如果您有一个动画必须跟随滚动位置,因为如果没有原生驱动程序,由于 React Native 的异步性质,它将始终比手势慢一帧。

之前

<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }]
)}
>
{content}
</ScrollView>

之后

<Animated.ScrollView // <-- Use the Animated ScrollView wrapper
scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }],
{ useNativeDriver: true } // <-- Add this
)}
>
{content}
</Animated.ScrollView>

注意事项

并非所有可以使用 Animated 实现的功能目前都受 Native Animated 支持。主要的限制是您只能动画非布局属性,例如 transformopacity 会起作用,但 Flexbox 和 position 属性不会。另一个是 Animated.event,它只适用于直接事件,而不适用于冒泡事件。这意味着它不适用于 PanResponder,但适用于 ScrollView#onScroll 等。

Native Animated 也已成为 React Native 的一部分很长时间了,但由于被认为是实验性的,从未被记录。因此,如果您想使用此功能,请确保您使用的是最新版本 (0.40+) 的 React Native。

资源

有关动画的更多信息,我建议观看 Christopher Chedeau 的这个演讲

如果您想深入了解动画以及如何将其卸载到原生以改善用户体验,还可以观看 Krzysztof Magiera 的这个演讲

React Native 应用的从右到左布局支持

·阅读约8分钟
Mengjue (Mandy) Wang
Facebook 软件工程师实习生

在应用发布到应用商店之后,国际化是进一步扩大受众范围的下一步。全球有超过 20 个国家和众多人使用从右到左 (RTL) 语言。因此,让你的应用支持 RTL 对他们来说是必要的。

我们很高兴地宣布,React Native 已经改进以支持 RTL 布局。这现在可在 react-native 的 master 分支中获取,并将在下一个 RC 版本中提供:v0.33.0-rc

这涉及更改 RN 使用的核心布局引擎 css-layout、RN 核心实现以及特定的开源 JS 组件以支持 RTL。

为了在生产环境中对 RTL 支持进行实战测试,最新版本的 Facebook Ads Manager 应用(第一个 100% RN 跨平台应用)现在已推出阿拉伯语和希伯来语版本,并支持 iOSAndroid 上的 RTL 布局。以下是它在这些 RTL 语言中的外观:

RN 中对 RTL 支持的更改概述

css-layout 已经有了布局的 startend 概念。在从左到右 (LTR) 布局中,start 表示 leftend 表示 right。但在 RTL 中,start 表示 rightend 表示 left。这意味着我们可以让 RN 依赖 startend 的计算来计算正确的布局,包括 positionpaddingmargin

此外,css-layout 已经让每个组件的方向继承自其父级。这意味着,我们只需将根组件的方向设置为 RTL,整个应用就会翻转。

下图描述了高层次的变化:

这包括:

通过此更新,当您允许您的应用程序使用 RTL 布局时:

  • 每个组件布局将水平翻转
  • 如果您使用支持 RTL 的开源组件,某些手势和动画将自动具有 RTL 布局
  • 可能需要最少的额外努力才能使您的应用程序完全支持 RTL

使应用支持 RTL

  1. 为了支持 RTL,您应该首先将 RTL 语言包添加到您的应用程序中。

  2. 通过在原生代码开头调用 allowRTL() 函数来允许您的应用程序使用 RTL 布局。我们提供了此实用程序,以便仅在您的应用程序准备就绪时才应用 RTL 布局。这是一个示例:

    iOS

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. 对于 Android,你需要在 AndroidManifest.xml 文件中的 <application> 元素中添加 android:supportsRtl="true"

现在,当您重新编译应用程序并将设备语言更改为 RTL 语言(例如阿拉伯语或希伯来语)时,您的应用程序布局应该会自动更改为 RTL。

编写支持 RTL 的组件

通常,大多数组件已经支持 RTL,例如:

  • 从左到右布局
  • 从右到左布局

然而,有几种情况需要注意,你将需要 I18nManager。在 I18nManager 中,有一个常量 isRTL 来判断应用的布局是否是 RTL,这样你就可以根据布局进行必要的更改。

具有方向含义的图标

如果您的组件有图标或图像,它们在 LTR 和 RTL 布局中的显示方式将相同,因为 RN 不会翻转您的源图像。因此,您应该根据布局样式翻转它们。

  • 从左到右布局
  • 从右到左布局

以下是根据方向翻转图标的两种方法:

  • 给图像组件添加 transform 样式

    <Image
    source={...}
    style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
    />
  • 或者,根据方向改变图像源

    let imageSource = require('./back.png');
    if (I18nManager.isRTL) {
    imageSource = require('./forward.png');
    }
    return <Image source={imageSource} />;

手势和动画

在 Android 和 iOS 开发中,当你切换到 RTL 布局时,手势和动画与 LTR 布局相反。目前,在 RN 中,手势和动画不支持 RN 核心代码级别,而是在组件级别。好消息是,其中一些组件已经支持 RTL,例如 SwipeableRowNavigationExperimental。然而,其他具有手势的组件将需要手动支持 RTL。

一个很好的手势 RTL 支持的例子是 SwipeableRow

手势示例
// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
动画示例
// SwipeableRow.js
_animateBounceBack(duration: number): void {
// ...
const swipeBounceBackDistance = IS_RTL ?
-RIGHT_SWIPE_BOUNCE_BACK_DISTANCE :
RIGHT_SWIPE_BOUNCE_BACK_DISTANCE;
this._animateTo(
-swipeBounceBackDistance,
duration,
this._animateToClosedPositionDuringBounce,
);
},

维护你的 RTL 兼容应用

即使在最初发布 RTL 兼容应用之后,你可能仍需要迭代新功能。为了提高开发效率,I18nManager 提供了 forceRTL() 函数,可以在不更改测试设备语言的情况下更快地进行 RTL 测试。你可能希望在你的应用中为此提供一个简单的开关。以下是 RNTester 中 RTL 示例的一个例子:

<RNTesterBlock title={'Quickly Test RTL Layout'}>
<View style={styles.flexDirectionRow}>
<Text style={styles.switchRowTextView}>forceRTL</Text>
<View style={styles.switchRowSwitchView}>
<Switch
onValueChange={this._onDirectionChange}
style={styles.rightAlignStyle}
value={this.state.isRTL}
/>
</View>
</View>
</RNTesterBlock>;

_onDirectionChange = () => {
I18nManager.forceRTL(!this.state.isRTL);
this.setState({isRTL: !this.state.isRTL});
Alert.alert(
'Reload this page',
'Please reload this page to change the UI direction! ' +
'All examples in this app will be affected. ' +
'Check them out to see what they look like in RTL layout.',
);
};

在开发新功能时,你可以轻松切换此按钮并重新加载应用以查看 RTL 布局。好处是你无需更改语言设置即可进行测试,但是某些文本对齐不会改变,如下一节所述。因此,在发布之前,始终最好在 RTL 语言中测试你的应用。

限制和未来计划

RTL 支持应该涵盖您应用程序中的大部分用户体验;但是,目前存在一些限制:

  • 文本对齐行为在 Android 和 iOS 中有所不同
    • 在 iOS 中,默认文本对齐方式取决于活动的语言包,它们始终在一侧。在 Android 中,默认文本对齐方式取决于文本内容的语言,即英语将左对齐,阿拉伯语将右对齐。
    • 理论上,这应该在跨平台保持一致,但有些人在使用应用程序时可能更喜欢一种行为而不是另一种。可能需要更多的用户体验研究来找出文本对齐的最佳实践。
  • 没有“真正的”左/右

    如前所述,我们将 JS 端的 left/right 样式映射到 start/end,代码中所有用于 RTL 布局的 left 在屏幕上变为“right”,代码中的 right 在屏幕上变为“left”。这很方便,因为你不需要过多地更改你的产品代码,但这意味着无法在代码中指定“真正的左”或“真正的右”。将来,允许组件独立于语言控制其方向可能是必要的。

  • 使手势和动画的 RTL 支持更具开发人员友好性

    目前,使手势和动画与 RTL 兼容仍需要一些编程工作。未来,理想的做法是找到一种方法,使手势和动画的 RTL 支持更具开发人员友好性。

试一试!

查看 RNTester 中的 RTLExample 以了解更多关于 RTL 支持的信息,并告诉我们它是如何为你工作的!

最后,感谢您的阅读!我们希望 React Native 对 RTL 的支持能帮助您为国际受众发展您的应用程序!