Skip to main content

关于新架构

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

¥Since 2018, the React Native team has been redesigning the core internals of React Native to enable developers to create higher-quality experiences. As of 2024, this version of React Native has been proven at scale and powers production apps by Meta.

新架构一词既指新的框架架构,也指将其开源的工作。

¥The term New Architecture refers to both the new framework architecture and the work to bring it to open source.

React Native 0.68 起,新架构已可供实验性选择加入,并在每个后续版本中不断改进。该团队现在正在努力使其成为 React Native 开源生态系统的默认体验。

¥The New Architecture has been available for experimental opt-in as of React Native 0.68 with continued improvements in every subsequent release. The team is now working to make this the default experience for the React Native open source ecosystem.

为何采用新架构?

¥Why a New Architecture?

经过多年使用 React Native 进行构建后,团队发现了一系列限制,阻碍了开发者精心打造某些体验。这些限制是框架现有设计的基础,因此新架构最初是作为对 React Native 未来的投资。

¥After many years of building with React Native, the team identified a set of limitations that prevented developers from crafting certain experiences with a high polish. These limitations were fundamental to the existing design of the framework, so the New Architecture started as an investment in the future of React Native.

新架构释放了传统架构中不可能实现的功能和改进。

¥The New Architecture unlocks capabilities and improvements that were impossible in the legacy architecture.

同步布局和效果

¥Synchronous Layout and Effects

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

¥Building adaptive UI experiences often requires measuring the size and position of your views and adjusting layout.

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

¥Today, you would use the onLayout event to get the layout information of a view and make any adjustments. However, state updates within the onLayout callback may apply after painting the previous render. This means that users may see intermediate states or visual jumps between rendering the initial layout and responding to layout measurements.

使用新架构,我们可以通过同步访问布局信息和正确计划的更新来完全避免此问题,这样用户就看不到中间状态。

¥With the New Architecture, we can avoid this issue entirely with synchronous access to layout information and properly scheduled updates such that no intermediate state is visible to users.

Example: Rendering a Tooltip

通过测量并在视图上方放置工具提示,我们可以展示同步渲染的解锁内容。工具提示需要知道其目标视图的位置,以确定它应该渲染的位置。

¥Measuring and placing a tooltip above a view allows us to showcase what synchronous rendering unlocks. The tooltip needs to know the position of its target view to determine where it should render.

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

¥In the current architecture, we use onLayout to get the measurements of the view and then update the positioning of the tooltip based on where the view is.

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 在一次提交中同步测量和应用布局更新,从而避免视觉上的 "jump"。

¥With the New Architecture, we can use useLayoutEffect to synchronously measure and apply layout updates in a single commit, avoiding the visual "jump".

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
Asynchronous measurement and render of the ToolTip. See code.
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.
Synchronous measurement and render of the ToolTip. See code.

支持并发渲染器和功能

¥Support for Concurrent Renderer and Features

新架构支持并发渲染以及 React 18 及更高版本中提供的功能。现在,你可以在 React Native 代码中使用 Suspense 等功能进行数据获取、转换和其他新的 React API,从而进一步使 Web 和原生 React 开发之间的代码库和概念保持一致。

¥The New Architecture supports concurrent rendering and features that have shipped in React 18 and beyond. You can now use features like Suspense for data-fetching, Transitions, and other new React APIs in your React Native code, further conforming codebases and concepts between web and native React development.

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

¥The concurrent renderer also brings out-of-the-box improvements like automatic batching, which reduces re-renders in React.

Example: Automatic Batching

借助新架构,你将使用 React 18 渲染器获得自动批处理。

¥With the New Architecture, you'll get automatic batching with the React 18 renderer.

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

¥In this example, a slider specifies how many tiles to render. Dragging the slider from 0 to 1000 will fire off a quick succession of state updates and re-renders.

在比较 相同的代码 的渲染器时,你可以直观地注意到渲染器提供了更流畅的 UI,中间 UI 更新更少。来自原生事件处理程序的状态更新(例如原生 Slider 组件)现在已批量更新。

¥In comparing the renderers for the same code, you can visually notice the renderer provides a smoother UI, with less intermediate UI updates. State updates from native event handlers, like this native Slider component, are now batched.

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.
Rendering frequent state updates with legacy renderer.
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.
Rendering frequent state updates with React 18 renderer.

新的并发功能(例如 过渡)使你能够表达 UI 更新的优先级。将更新标记为较低优先级告诉 React 它可以 "interrupt" 渲染更新来处理较高优先级的更新,以确保在重要的地方提供响应式的用户体验。

¥New concurrent features, like Transitions, give you the power to express the priority of UI updates. Marking an update as lower priority tells React it can "interrupt" rendering the update to handle higher priority updates to ensure a responsive user experience where it matters.

Example: Using startTransition

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

¥We can build on the previous example to showcase how transitions can interrupt in-progress rendering to handle a newer state update.

我们用 startTransition 封装图块编号状态更新,以指示可以中断图块的渲染。startTransition 还提供了 isPending 标志来告诉我们转换何时完成。

¥We wrap the tile number state update with startTransition to indicate that rendering the tiles can be interrupted. startTransition also provides a isPending flag to tell us when the transition is complete.

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 渲染的中间状态更少,因为一旦状态变旧,它就会停止渲染状态。相比之下,如果没有转换,则会渲染更多的中间状态。这两个示例仍然使用自动批处理。尽管如此,过渡为开发者提供了更多的权力来批量进行正在进行的渲染。

¥You'll notice that with the frequent updates in a transition, React renders fewer intermediate states because it bails out of rendering the state as soon as it becomes stale. In comparison, without transitions, more intermediate states are rendered. Both examples still use automatic batching. Still, transitions give even more power to developers to batch in-progress renders.

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.
Rendering tiles with transitions to interrupt in-progress renders of stale state. See code.
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.
Rendering tiles without marking it as a transition. See code.

快速 JavaScript/原生接口

¥Fast JavaScript/Native Interfacing

新架构删除了 JavaScript 和原生之间的 异步桥,并用 JavaScript Interface (JSI) 代替。JSI 是一个接口,允许 JavaScript 保存对 C++ 对象的引用,反之亦然。通过内存引用,你可以直接调用方法,而无需序列化成本。

¥The New Architecture removes the asynchronous bridge between JavaScript and native and replaces it with JavaScript Interface (JSI). JSI is an interface that allows JavaScript to hold a reference to a C++ object and vice-versa. With a memory reference, you can directly invoke methods without serialization costs.

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

¥JSI enables VisionCamera, a popular camera library for React Native, to process frames in real time. Typical frame buffers are 10 MB, which amounts to roughly 1 GB of data per second, depending on the frame rate. In comparison with the serialization costs of the bridge, JSI handles that amount of interfacing data with ease. JSI can expose other complex instance-based types such as databases, images, audio samples, etc.

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

¥JSI adoption in the New Architecture removes this class of serialization work from all native-JavaScript interop. This includes initializing and re-rendering native core components like View and Text. You can read more about our investigation in rendering performance in the New Architecture and the improved benchmarks we measured.

启用新架构后我可以期待什么?

¥What can I expect from enabling the New Architecture?

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

¥While the New Architecture enables these features and improvements, enabling the New Architecture for your app or library may not immediately improve the performance or user experience.

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

¥For example, your code may need refactoring to leverage new capabilities like synchronous layout effects or concurrent features. Although JSI will minimize the overhead between JavaScript and native memory, data serialization may not have been a bottleneck for your app's performance.

在你的应用或库中启用新架构就是选择 React Native 的未来。

¥Enabling the New Architecture in your app or library is opting into the future of React Native.

该团队正在积极研究和开发新架构释放的新功能。例如,Web 对齐是 Meta 的一个活跃探索字段,它将被交付到 React Native 开源生态系统。

¥The team is actively researching and developing new capabilities the New Architecture unlocks. For example, web alignment is an active area of exploration at Meta that will ship to the React Native open source ecosystem.

你可以关注我们的专用 讨论和建议 存储库并做出贡献。

¥You can follow along and contribute in our dedicated discussions & proposals repository.

我今天应该使用新架构吗?

¥Should I use the New Architecture today?

对于 0.76,新架构在所有 React Native 项目中默认启用。

¥With 0.76, The New Architecture is enabled by default in all the React Native projects.

如果你发现任何运行不正常的地方,请使用 此模板 打开问题。

¥If you find anything that is not working well, please open an issue using this template.

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

¥If, for any reasons, you can't use the New Architecture, you can still opt-out from it:

安卓

¥Android

  1. 打开 android/gradle.properties 文件

    ¥Open the android/gradle.properties file

  2. newArchEnabled 标志从 true 切换到 false

    ¥Toggle the newArchEnabled flag from true to 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 文件

    ¥Open the ios/Podfile file

  2. 在 Podfile 的主范围内添加 ENV['RCT_NEW_ARCH_ENABLED'] = '0'(模板中的 参考 Podfile

    ¥Add ENV['RCT_NEW_ARCH_ENABLED'] = '0' in the main scope of the Podfile (reference Podfile in the template)

+ 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 依赖:

    ¥Install your CocoaPods dependencies with the command:

bundle exec pod install