本文由 简悦 SimpRead转码,原文地址 www.callstack.com
了解尝试使用 React Native 新架构如何让您的应用程序面向未来并提高 ......以下文章是React Native 优化终极指南的一部分。它包括 React Native 核心团队的宝贵见解,阐述了尽早尝试使用 React Native 新架构的好处。
为什么这很重要?
您的应用程序使用的可能是旧架构,不具备 React 18 的并发功能。或者说 "当前 "架构可能更好一些,因为生产应用程序大多仍在使用它。无论如何,如果您选择了新架构,您就可以在应用程序中利用新呈现系统的功能--这将大大有利于您的产品并改善业务成果。在这篇博文中,我们将解释什么是新架构,以及它如何改进你的 React Native 项目。
在基于《React Native 优化终极指南》的其他博文中,我们将讨论以下与性能相关的主题:
- 使用 Gradle 设置优化 Android 应用程序的大小
- 使用 Hermes 优化 Android 应用程序的启动时间
- 使用 "Autolinking "自动管理依赖关系
- 使用 Flipper 更快更好地进行调试
- 为什么必须始终运行最新版本的 React Native?
查看这些内容!现在让我们进入正题。
新旧架构对比
新旧架构都基于 JavaScript 与原生侧之间的通信。目前,这种通信由桥接器处理。让我们回顾一下它的局限性,以便更好地理解新架构试图解决的问题:
- 它是异步的:JavaScript 端向桥接器提交数据,然后等待本地端处理数据。
- 它是单线程的,因此重要的是不要让 JavaScript 线程过载,也不要在 UI 线程上执行动画。
- 从 JSON 对象序列化数据时会增加额外的开销。
在大多数情况下,桥接器仍能正常工作。但是,当我们开始通过桥接器发送大量数据时,它可能会成为应用程序的瓶颈。在呈现长列表中的大量组件时就会出现这个问题。当用户快速滚动时,由于 JS 和本地端之间的通信是异步的,因此会出现空白。从本质上讲,我们的桥接器上会出现等待序列化的对象 "堵车 "现象。在 本地模块 来回发送大量数据时,也会出现桥接器 "超载 "的问题。
新架构试图解决的主要问题是这一瓶颈,以及在本地模块和 JS 之间提供一种类型安全的通信方式。不过,新架构并非都像看起来那么好。我们还将讨论它带来的弊端。
什么是新架构?
从 React Native 0.68 开始,开发人员可以利用框架的新功能。新架构 依赖于一系列工具,它们是新体验的关键组成部分。
其中最重要的两个工具是 Fabric 和 TurboModules。第一个是新的渲染系统,第二个是编写本地模块的新方法。我们将在本节后面详细介绍。
Codegen 和 JSI 是改善开发者体验的两个新工具。它们对于了解新架构的工作原理至关重要。Codegen 通过生成大量本地模板代码并确保类型安全,极大地改进了 DX。而 JSI 是一个用于与任何 JS 引擎交互的 C++ API。
注:在 React Native v0.71+ 之前,在应用程序中部署新架构是可能的,但难度很大。因此,我们建议您升级到这个版本。
代码生成工具
一款代码生成工具,通过自动实现 JS 与本地端之间的兼容,让 JS 成为真正的源代码。它允许编写静态类型的 JS(称为 JS Spec),然后用于生成 Fabric 本地组件和 TurboModules 所需的接口文件。Spec 包括一组用 TypeScript 或 Flow 编写的类型,定义了原生模块提供的所有 API。
Codegen确保了类型安全和编译时类型安全,这意味着 更小的代码和更快的执行,因为两个领域在每次验证数据时都可以相互信任。要了解更多信息,请参阅 文档。
JSI
JSI 是新架构的基础,是与任何 JS 引擎交互的 C++ API。与异步的桥接相比,JSI 是同步的,这样可以更快地调用本地函数。它允许 JavaScript 持有对 C++ 主对象的引用,并直接调用它们的方法。通过使用桥接器对对象进行序列化,这就消除了 JS 和本地之间异步通信的主要开销。
Fabric
Fabric 是 React Native 新的并发渲染系统,是传统渲染系统的概念演进。其核心原则是在 C++ 中统一更多的呈现逻辑,以更好地利用平台间的互操作性。现在,View、Text 等主机组件都是懒散初始化的,因此启动速度更快。Fabric 允许我们利用 React 18 中引入的功能。
TurboModules
这是一种编写原生模块的新方法,它还利用了 JSI 的强大功能,允许从原生模块到 JS(反之亦然)进行同步数据传输,速度快了一个数量级。
它重写了 JavaScript 与蓝牙、生物识别等平台本地模块之间的通信层。它还允许使用 C++ 为两个平台编写本地代码,并引入了模块的懒加载功能,以加快应用程序的启动时间。
无桥模式
目前,React Native 并没有完全移除桥接器;它仍然存在,允许开发人员逐步采用新的架构和 JSI。不过,桥接器的使用需要明确说明(通过导入),因此尚未迁移的模块将无法使用。
Meta 计划很快允许应用程序在完全无桥模式下运行,这将消除每次启动应用程序时加载桥的开销,从而加快应用程序的启动速度。
如何开启新架构
要在应用程序中启用新架构,您需要将应用程序至少升级到 React Native 0.68;不过,我们建议您至少升级到 React Native 0.71 以上,因为其中添加了大量改进。
要将应用程序迁移到新架构,请按照以下步骤操作:
- 将您的应用程序至少升级到 React Native 0.71+,您可以使用 react-native-community.github.io/upgrade-hel…
- 检查应用程序依赖的所有第三方库;重要的是所有这些库都需要迁移!这可能是很多应用程序长期以来的障碍。尚未兼容的组件会显示一个红框--
Unimplemented component: <ComponentName>- 您可能会注意到它们。在这种情况下,请告知程序库维护者,这将加快采用速度。 - [Android] 在
gradle.properties中设置newArchEnabled=true。 - [iOS] 在 iOS 文件夹内运行
RCT_NEW_ARCH_ENABLED=1 pod install。
将 React Native 应用程序移至新架构的好处
现在您已经知道新架构是如何工作的了,让我们来看看它的好处。
性能
由于新架构的同步特性,在与原生端通信时,性能会有一些提升。由于每个原生模块都将被懒加载,应用程序的启动时间将大大缩短。一旦无桥模式可用,还将消除启动时加载桥的开销。不过,并非所有情况都能证明这一点;在某些基准测试中,架构性能反而更差。
Meta 的目标不是让新架构比旧架构快 X 倍。除了消除主要瓶颈外,他们还希望创建一个新的坚实基础,从而实现以前的架构无法开发的新功能。迁移 Facebook 应用程序花了一年多的时间,他们没有发现任何明显的性能改进,也没有发现任何终端用户可以感知到的性能倒退。不过,这并不意味着未来不会出现性能改进。现在,他们对内部结构进行了重新设计,有了一个很好的基础。
让我们来看看 BAM 的 Alexandre Moureaux提供的一些性能基准测试。下面是源文件的链接: github.com/reactwg/rea…
渲染 10K 视图的基准测试
在这种情况下,事实证明新架构比旧架构更高效。平均使用的 CPU 更少,但内存更大。
渲染 2K 文本组件的基准测试
在这种情况下,旧架构速度更快,因为 UI 线程消耗更多。
React Native 团队的官方回应是,他们在向用户推出新架构时进行了内部基准测试,结果显示安卓和 iOS 平台上 Facebook 应用程序中的所有 React Native 表面均保持中立。正如 Samuel Susla 在本讨论主题中所说:"在过去几年中,我们在数百万台设备上进行了数十次生产测试,以确保性能是中性的"。
因此,在大多数使用案例中,您可以预期对性能的影响是中性的,不会出现任何性能下降。请记住,新架构每天都在不断完善,许多开发人员都为版本库做出了贡献,所以当你读到这篇文章时,结果可能已经完全不同了。
未来准备就绪
新架构 允许您的应用程序利用并发 React 功能。这将提高 UI 响应速度,为数据获取提供暂停功能,以处理复杂的 UI 加载方案,并确保您的应用已为 React 18 中引入的新并发引擎之上的任何进一步 React 创新做好准备。
让我们看看如何利用 React18 的 startTransition API 在两个状态更新之间确定优先级。在我们的示例中,按钮点击可视为紧急更新,而 NonUrgentUI 可视为非紧急更新。要告诉 React 非紧急更新,我们可以在 startTransition API 中封装 setState。这样,React 就能准备好新的用户界面并显示旧的用户界面,直到新的用户界面准备好为止。
在我们的示例中,我们在 start-Transition 中封装了 setNonUrgentValue,并告诉 React,nonUrgentValue 是一个过渡,并不那么紧急,可能需要一些时间。我们还添加了条件背景色。运行此示例时,您会看到一旦点击按钮,视图将保留其原有的用户界面,例如,如果我们从值 1 开始,用户界面将是绿色的。
点击按钮后,Value 文本的用户界面将被更新,但容器的用户界面将保持绿色,直到转换完成,由于新的用户界面正在渲染,颜色将变为红色。这就是 React 并发呈现的神奇之处。
为了更好地理解它,请假设在 startTransition 中封装更新会在不同的宇宙中呈现。我们不会直接看到那个宇宙,但我们可以使用 useTransition 钩子返回的 isPending 变量从它那里获取信号。一旦新的用户界面准备就绪,两个宇宙就会合并在一起,显示最终的用户界面。
import React from "react";
import { Button, StyleSheet, Text, View } from "react-native";
const dummyData = Array(10000).fill(1);
const NonUrgentUI = ({ value, isPending }) => {
const backgroundStyle = {
backgroundColor: value % 2 === 0 ? "red" : "green",
};
return (
<View>
<Text>Non urgent update value: {isPending ? "PENDING" : value}</Text>
<View style={[styles.container, backgroundStyle]}>
{dummyData.map((_, index) => (
<View key={index} style={styles.item} />
))}
</View>
</View>
);
};
const ConcurrentStartTransition = () => {
const [value, setValue] = React.useState(1);
const [nonUrgentValue, setNonUrgentValue] = React.useState(1);
const [isPending, startTransition] = React.useTransition();
const handleClick = () => {
const newValue = value + 1;
setValue(newValue);
startTransition(() => {
setNonUrgentValue(newValue);
});
};
return (
<View>
<Button onPress={handleClick} title="Increment value" />
<Text>Value: {value}</Text>
<NonUrgentUI value={nonUrgentValue} isPending={isPending} />
</View>
);
};
export default ConcurrentStartTransition;
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
},
item: {
width: 10,
height: 10,
},
});
为了更好地理解,让我们把刚才的代码片段可视化一下。下图显示了使用 startTransition 和不使用 startTransition 时的对比。从图中我们可以看到,React 会立即刷新紧急更新,这是因为调用 setValue 时未将其封装在 startTransition 中。
接下来,我们会看到 React 为依赖于非紧急更新的用户界面(也就是用 startTransition 封装的更新)显示了旧的用户界面(绿色)。我们还看到显示了一个 Pending 文本;这是 React18 告诉我们依赖于此状态的新用户界面尚未准备就绪的一种方式。一旦准备就绪,React 就会刷新它,我们就不会再看到 Pending 文本,视图颜色也会变为红色。
另一方面,如果我们不使用 startTransition,React 会尝试将两个更新都作为紧急更新处理,并在两个更新都准备就绪后刷新。这样做肯定会有一些弊端,比如应用程序会尝试一次性呈现一些繁重的 UI,这可能会给用户带来不协调的效果。有了 React18,我们可以通过延迟非紧急更新来解决这个问题。
React18 中还有其他一些值得注意的功能,您可能想通过使用 React 官方网站上的链接沙盒来了解一下。请参见 useDeferredValue 和 startTransition with Suspense。
维护与支持
React Native 核心团队致力于为 React Native 的 3 个最新版本提供支持(您可以查看支持政策 此处),React 核心团队还计划在并发渲染引擎的基础上开发新功能。重要的是不要落在后面,因为支付技术债务的成本会随着时间的推移而增加。值得指出的是,React Native 在这方面与其他软件项目并无不同。在不可避免的情况下,不更新依赖关系不仅会让您的团队在这项任务上花费更多时间,还会让您的应用程序面临安全威胁。它还可能使您的应用程序暴露于上游已打补丁的安全漏洞中。
React Native 团队有专门的能力与社区密切合作,帮助他们解决应用程序和库在采用新架构时遇到的问题。虽然它还不稳定,但值得考虑尽早开始计划迁移,这样你就能找出你的应用程序可能面临的问题和障碍。2023 年是尝试、评估、寻求支持和提供反馈的最佳时机。
React Native 核心工程师会为您提供良好的支持,帮助您解决应用程序在构建和运行时遇到的阻碍迁移的问题,让您抢占先机。一旦新架构趋于稳定并默认开启,核心团队必将专注于 React Native 的进一步开发,从而缩短迁移支持时间。
需要性能方面的帮助?请联系我们!
如果你正在为提高应用程序性能而苦恼,请与我们联系。我们的 React Native 开发公司 是 Meta 的官方合作伙伴和社区领导者。我们已经为数十家国际客户(从初创公司到企业)提供了高质量的解决方案,并创建了一些很酷的开源项目,如 Re.Pack 或 Reassure。现在正是我们帮助您的企业成长的时候。