跳到主要内容

关于新架构

自2018年以来,React Native团队一直在重新设计React Native的核心内部结构,以使开发者能够创建更高质量的体验。截至2024年,此版本的React Native已在大规模应用中得到验证,并为Meta的生产应用程序提供支持。

术语新架构既指新的框架架构,也指将其引入开源的工作。

新架构已在React Native 0.68中可供实验性选择启用,并在后续的每个版本中持续改进。该团队目前正努力将其作为React Native开源生态系统的默认体验。

为什么选择新架构?

经过多年使用React Native的开发,团队发现了一系列限制,这些限制阻碍了开发人员打造某些高度精细的体验。这些限制是现有框架设计的根本,因此新架构最初是对React Native未来的一项投资。

新架构解锁了旧架构中无法实现的功能和改进。

同步布局和效果

构建自适应UI体验通常需要测量视图的大小和位置并调整布局。

目前,您会使用onLayout事件来获取视图的布局信息并进行任何调整。然而,onLayout回调中的状态更新可能会在绘制上一个渲染之后应用。这意味着用户可能会看到中间状态或在渲染初始布局和响应布局测量之间出现视觉跳动。

通过新架构,我们可以通过同步访问布局信息和适当调度的更新来完全避免此问题,从而确保用户看不到任何中间状态。

示例:渲染工具提示

测量并将工具提示放置在视图上方,可以展示同步渲染所带来的可能性。工具提示需要知道其目标视图的位置才能确定其渲染位置。

在当前架构中,我们使用onLayout来获取视图的测量值,然后根据视图的位置更新工具提示的位置。

jsx
function ViewWithTooltip() {
// ...

// We get the layout information and pass to ToolTip to position itself
const onLayout = React.useCallback(event => {
targetRef.current?.measureInWindow((x, y, width, height) => {
// This state update is not guaranteed to run in the same commit
// This results in a visual "jump" as the ToolTip repositions itself
setTargetRect({x, y, width, height});
});
}, []);

return (
<>
<View ref={targetRef} onLayout={onLayout}>
<Text>Some content that renders a tooltip above</Text>
</View>
<Tooltip targetRect={targetRect} />
</>
);
}

通过新架构,我们可以使用useLayoutEffect来同步测量并在一次提交中应用布局更新,从而避免视觉“跳动”。

jsx
function ViewWithTooltip() {
// ...

useLayoutEffect(() => {
// The measurement and state update for `targetRect` happens in a single commit
// allowing ToolTip to position itself without intermediate paints
targetRef.current?.measureInWindow((x, y, width, height) => {
setTargetRect({x, y, width, height});
});
}, [setTargetRect]);

return (
<>
<View ref={targetRef}>
<Text>Some content that renders a tooltip above</Text>
</View>
<Tooltip targetRect={targetRect} />
</>
);
}
A view that is moving to the corners of the viewport and center with a tooltip rendered either above or below it. The tooltip is rendered after a short delay after the view moves
工具提示的异步测量和渲染。查看代码
A view that is moving to the corners of the viewport and center with a tooltip rendered either above or below it. The view and tooltip move in unison.
工具提示的同步测量和渲染。查看代码

支持并发渲染器和功能

新架构支持在React 18及更高版本中发布的并发渲染和功能。您现在可以在React Native代码中使用诸如Suspense(用于数据获取)、Transitions等新React API,进一步统一Web和Native React开发的代码库和概念。

并发渲染器还带来了开箱即用的改进,例如自动批处理,这减少了React中的重新渲染。

示例:自动批处理

通过新架构,您将获得React 18渲染器的自动批处理功能。

在此示例中,滑块指定要渲染的图块数量。将滑块从0拖动到1000将触发一系列快速连续的状态更新和重新渲染。

通过比较相同代码的渲染器,您可以直观地注意到渲染器提供了更平滑的UI,中间UI更新更少。来自原生事件处理程序(例如此原生滑块组件)的状态更新现在已进行批处理。

A video demonstrating an app rendering many views according to a slider input. The slider value is adjusted from 0 to 1000 and the UI slowly catches up to rendering 1000 views.
使用旧渲染器渲染频繁的状态更新。
A video demonstrating an app rendering many views according to a slider input. The slider value is adjusted from 0 to 1000 and the UI resolves to 1000 views faster than the previous example, without as many intermediate states.
使用React 18渲染器渲染频繁的状态更新。

新的并发功能,如Transitions,让您能够表达UI更新的优先级。将更新标记为较低优先级会告诉React它可以“中断”渲染更新,以处理较高优先级的更新,从而在关键时刻确保响应式用户体验。

示例:使用startTransition

我们可以在上一个示例的基础上,展示过渡如何中断正在进行的渲染以处理新的状态更新。

我们用startTransition包裹图块数量的状态更新,以表明渲染图块可以被中断。startTransition还提供一个isPending标志,用于告知我们过渡何时完成。

jsx
function TileSlider({value, onValueChange}) {
const [isPending, startTransition] = useTransition();

return (
<>
<View>
<Text>
Render {value} Tiles
</Text>
<ActivityIndicator animating={isPending} />
</View>
<Slider
value={1}
minimumValue={1}
maximumValue={1000}
step={1}
onValueChange={newValue => {
startTransition(() => {
onValueChange(newValue);
});
}}
/>
</>
);
}

function ManyTiles() {
const [value, setValue] = useState(1);
const tiles = generateTileViews(value);
return (
<TileSlider onValueChange={setValue} value={value} />
<View>
{tiles}
</View>
)
}

您会注意到,在过渡中频繁更新时,React 渲染的中间状态较少,因为它一旦状态过时就放弃渲染该状态。相比之下,如果没有过渡,会渲染更多的中间状态。这两个示例仍然使用自动批处理。但是,过渡为开发者提供了更大的能力来批处理进行中的渲染。

A video demonstrating an app rendering many views (tiles) according to a slider input. The views are rendered in batches as the slider is quickly adjusted from 0 to 1000. There are less batch renders in comparison to the next video.
使用过渡渲染图块以中断正在进行的过期状态渲染。查看代码
A video demonstrating an app rendering many views (tiles) according to a slider input. The views are rendered in batches as the slider is quickly adjusted from 0 to 1000.
渲染图块但未将其标记为过渡。查看代码

快速JavaScript/原生接口

新架构移除了 JavaScript 和原生之间的异步桥,并将其替换为 JavaScript 接口 (JSI)。JSI 是一种允许 JavaScript 持有 C++ 对象引用(反之亦然)的接口。通过内存引用,您可以直接调用方法而无需序列化开销。

JSI 使 VisionCamera(一个流行的 React Native 相机库)能够实时处理帧。典型的帧缓冲区约为 30 MB,根据帧速率,每秒大约有 2 GB 的数据。与桥接的序列化成本相比,JSI 可以轻松处理如此大量的数据接口。JSI 可以公开其他复杂的基于实例的类型,例如数据库、图像、音频样本等。

新架构中采用 JSI 消除了所有原生-JavaScript 互操作中的此类序列化工作。这包括初始化和重新渲染原生核心组件,如 ViewText。您可以在我们的关于新架构中渲染性能的调查中阅读更多信息以及我们测量的改进基准。

启用新架构后,我能期待什么?

虽然新架构支持这些功能和改进,但为您的应用或库启用新架构可能不会立即提高性能或用户体验。

例如,您的代码可能需要重构才能利用同步布局效果或并发功能等新功能。尽管 JSI 会最大限度地减少 JavaScript 和原生内存之间的开销,但数据序列化可能不是您的应用程序性能瓶颈。

在您的应用或库中启用新架构,即表示您选择拥抱 React Native 的未来。

团队正在积极研究和开发新架构解锁的新功能。例如,Web 对齐是 Meta 正在探索的活跃领域,它将发布到 React Native 开源生态系统。

您可以在我们专门的讨论和提案仓库中关注并贡献。

我现在应该使用新架构吗?

在 0.76 版本中,新架构已在所有 React Native 项目中默认启用。

如果您发现任何问题,请使用此模板提交问题。

如果出于任何原因,您无法使用新架构,您仍然可以选择退出它

Android

  1. 打开android/gradle.properties文件
  2. newArchEnabled 标志从 true 切换为 false
gradle.properties
# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
-newArchEnabled=true
+newArchEnabled=false

iOS

  1. 打开 ios/Podfile 文件
  2. 在 Podfile 的主作用域中添加 ENV['RCT_NEW_ARCH_ENABLED'] = '0'模板中的参考 Podfile
差异
+ ENV['RCT_NEW_ARCH_ENABLED'] = '0'
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
  1. 使用命令安装您的 CocoaPods 依赖项
shell
bundle exec pod install