跳至主内容

全新架构正式发布

· 1 分钟阅读
The React Team
The React Team
@reactjs / @reactnative
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

React Native 0.76 现已正式登陆 npm,全新架构成为默认配置!

我们在0.76版本发布公告中详细介绍了此版本的重要变更。本文将带您纵览全新架构的全貌,解读它如何重塑React Native的未来蓝图。

全新架构全面支持现代React特性,包括悬停(Suspense)过渡(Transitions)自动批处理(automatic batching)以及useLayoutEffect。同时引入了全新的原生模块(Native Module)原生组件(Native Component)系统,让您能编写类型安全的代码,无需桥接即可直接访问原生接口。

本次发布是我们自2018年启动的React Native底层重构的成果结晶,我们特别注重确保大多数应用都能渐进式迁移至新架构。2021年,我们成立了新架构工作组,与社区通力合作,为整个React生态提供无缝升级体验。

绝大多数应用迁移至React Native 0.76的工作量与常规版本更新相当。主流React Native库均已支持新架构,同时内置的自动互操作层确保了对旧架构库的向后兼容性。

过去数年的开发历程中,我们团队多次公开分享新架构的愿景规划。若您错过了这些精彩分享,请点击查看:

全新架构解析

全新架构是对React Native底层核心系统的全面重构,涵盖组件渲染机制、JavaScript与原生抽象层的通信方式,以及多线程任务调度策略。尽管大多数用户无需关注这些系统的实现细节,但这些变革带来了显著的性能提升与功能突破。

在旧版架构中,React Native通过异步桥接机制与原生平台通信。无论是渲染组件还是调用原生函数,都需要先将函数调用序列化并加入桥接队列,以异步方式进行处理。这种设计的优势在于主线程永远不会因渲染更新或原生模块调用而阻塞,所有任务均在后台线程完成。

然而,用户期望交互获得即时反馈以实现原生应用般的体验。这意味着某些更新需要同步响应用户输入立即渲染,甚至可能中断正在进行的渲染任务。由于旧架构仅支持异步更新机制,我们必须重构系统以同时支持异步和同步更新。

此外,在旧架构中,通过桥接器序列化函数调用很快成为性能瓶颈,尤其在频繁更新或处理大型对象时。这使得应用难以稳定实现 60+ FPS 的帧率。同时存在同步问题:当 JavaScript 层与原生层状态不一致时,无法同步协调两者,导致出现诸如列表显示空白帧、因中间状态渲染引发的界面跳动等错误。

最后,由于旧架构使用单一原生层级树维护 UI 状态并进行原地修改,布局计算只能限定在单一线程。这导致无法处理用户输入等紧急更新,也无法同步读取布局信息(例如在布局效果中读取位置以更新工具提示)。

这些问题意味着无法完整支持 React 的并发特性。为解决这些挑战,新架构包含四大核心改进:

  • 全新原生模块系统

  • 全新渲染器

  • 事件循环机制

  • 桥接器移除

全新模块系统让 React Native 渲染器能够同步访问原生层,从而支持异步/同步处理事件、调度更新及读取布局。新原生模块默认支持懒加载,显著提升应用性能。

全新渲染器可在多线程并行处理多个渲染树,使 React 能够在主线程或后台线程处理不同优先级的并发更新。同时支持多线程同步/异步读取布局信息,实现更流畅无卡顿的响应式 UI。

新事件循环机制可在 JavaScript 线程按明确定义的顺序处理任务。这使得 React 能够中断渲染以优先处理紧急用户事件(如高于低优先级 UI 转场动画)。该机制也遵循 Web 规范,可支持微任务、MutationObserverIntersectionObserver 等浏览器特性。

最后,移除桥接器不仅加快启动速度,还实现 JavaScript 与原生运行时的直接通信,最大限度减少任务切换开销。同时改进错误报告与调试能力,减少未定义行为导致的崩溃。

新架构现已具备生产环境使用条件。Meta 已在 Facebook 应用及其他产品中大规模应用,并在为 Quest 设备开发的 Facebook 和 Instagram 应用中成功实践。

我们的合作伙伴已在新架构生产环境运行数月:可参考 ExpensifyKraken 的成功案例,并体验 Bluesky 的最新版本。

全新原生模块系统

全新原生模块系统彻底重构了 JavaScript 与原生平台的通信机制,完全基于 C++ 实现并具备以下能力:

  • 支持原生运行时的双向同步访问

  • JavaScript 与原生代码间的类型安全

  • 跨平台代码共享

  • 默认支持模块懒加载

通过全新原生模块系统,JavaScript 与原生层现在可通过 JavaScript 接口(JSI)直接同步通信,无需依赖异步桥接器。这意味着您的自定义原生模块可同步调用函数、返回值并将结果传递给其他原生模块。

在旧架构中,处理原生函数调用响应需通过回调机制,且返回值必须支持序列化:

// ❌ Sync callback from Native Module
nativeModule.getValue(value => {
// ❌ value cannot reference a native object
nativeModule.doSomething(value);
});

在新架构中,您可以对原生函数进行同步调用:

// ✅ Sync response from Native Module
const value = nativeModule.getValue();

// ✅ value can be a reference to a native object
nativeModule.doSomething(value);

借助新架构,您终于可以在通过 JavaScript/TypeScript API 访问的同时,充分发挥 C++ 原生实现的全部能力。全新模块系统支持使用 C++ 编写的模块,因此您可以一次编写模块,即可在 Android、iOS、Windows 和 macOS 等全平台运行。采用 C++ 实现模块能够进行更精细的内存管理和性能优化。

此外,通过代码生成器(Codegen),您的模块可以在 JavaScript 层与原生层之间建立强类型契约。根据我们的经验,跨边界类型错误是跨平台应用中最常见的崩溃来源之一。Codegen 不仅能自动生成样板代码,还能帮助您规避这类问题。

最后,模块现在支持延迟加载:它们仅在真正需要时才会被载入内存,而非在应用启动时就全部加载。这显著减少了应用启动时间,并确保随着应用复杂度增长,启动时间仍保持较低水平。

流行库如 react-native-mmkv 已从迁移到新原生模块中获得显著收益:

"新原生模块极大简化了 react-native-mmkv 的设置、自动链接和初始化流程。得益于新架构,react-native-mmkv 现在成为纯 C++ 原生模块,可在任意平台运行。全新的 Codegen 实现了完全类型安全,通过强制空值安全修复了长期存在的 NullPointerReference 问题,而同步调用原生模块函数的能力让我们得以用新的原生模块 API 替代自定义 JSI 访问方案。"

—— Marc Rousavyreact-native-mmkv 创建者

全新渲染引擎

我们还彻底重写了原生渲染引擎,带来多项优势:

  • 更新可在不同线程以不同优先级渲染

  • 布局信息支持跨线程同步读取

  • 渲染引擎采用 C++ 编写并在全平台共享

升级后的原生渲染引擎现在将视图层级存储在不可变的树状结构中。这意味着 UI 以不可直接修改的方式存储,允许安全地多线程处理更新。这使其能够同时处理多个进行中的渲染树,每棵树代表用户界面的不同版本。因此,更新可在后台渲染而不阻塞 UI(如在转场动画期间),也可在主线程渲染(如响应用户输入)。

通过支持多线程,React 可以中断低优先级更新来渲染紧急更新(例如用户输入触发的更新),随后再根据需要恢复低优先级更新。新渲染引擎还能跨线程同步读取布局信息,这既支持低优先级更新的后台计算,也能满足同步读取需求(例如调整工具提示位置)。

最后,使用 C++ 重写渲染引擎使其能在所有平台共享。这确保了相同代码在 iOS、Android、Windows、macOS 等所有 React Native 支持的平台上运行,提供一致的渲染能力,无需为每个平台重新实现。

这是我们实现多平台愿景的重要一步。例如视图扁平化(View Flattening)曾是 Android 独有的优化技术,用于避免深层布局树。拥有共享 C++ 核心的新渲染引擎将该功能引入 iOS。这项优化完全自动生效且无需配置,共享渲染引擎使其天然具备这一优势。

通过这些改进,React Native 现已全面支持并发渲染特性(如 Suspense 和 Transitions),让您更轻松地构建复杂用户界面,快速响应用户输入且无卡顿、延迟或视觉跳跃。未来我们将利用这些新能力,为 FlatList 和 TextInput 等内置组件带来更多优化。

Reanimated 这样的流行库已经开始利用新渲染器:

"目前正在开发中的 Reanimated 4 引入了全新的动画引擎,它直接与新渲染器协同工作,使其能够跨线程处理动画和管理布局。新渲染器的设计真正实现了无需大量变通方案即可构建这些功能。此外,由于采用 C++ 实现并跨平台共享,Reanimated 的大部分代码只需编写一次,从而减少平台特定问题、精简代码库并简化对树外平台的适配。"

Krzysztof MagieraReanimated 创造者

事件循环

新架构使我们能够实现定义明确的事件循环处理模型,如这份 RFC 所述。该 RFC 遵循 HTML 标准 中的规范,明确了 React Native 在 JavaScript 线程上执行任务的方式。

定义明确的事件循环弥合了 React DOM 与 React Native 之间的差异:现在 React Native 应用的行为更接近 React DOM 应用,真正实现了"一次学习,随处编写"。

事件循环为 React Native 带来诸多优势:

  • 能够中断渲染以处理事件和任务

  • 与 Web 规范更紧密对齐

  • 为更多浏览器功能奠定基础

借助事件循环,React 能够可预测地编排更新和事件顺序。这使得 React 可以中断低优先级更新来处理紧急用户事件,而新渲染器则允许我们独立渲染这些更新。

事件循环还将定时器等事件和任务的行为与 Web 规范对齐,这意味着 React Native 的工作方式更符合 Web 用户的预期,并促进了 React DOM 与 React Native 之间更好的代码共享。

这也为实现更符合规范的浏览器功能(如微任务、MutationObserverIntersectionObserver)提供了可能。虽然这些功能尚未在 React Native 中可用,但我们正在努力在未来版本中提供支持。

最后,事件循环及新渲染器对同步读取布局的支持,使 React Native 能够为 useLayoutEffect 提供完善支持——同步读取布局信息并在同一帧内更新 UI,确保元素在显示给用户前已正确定位。

更多详情请参阅 useLayoutEffect

移除桥接层

在新架构中,我们完全移除了 React Native 对桥接层的依赖,转而使用 JSI 实现 JavaScript 与原生代码之间的直接高效通信:

移除桥接层通过避免桥接初始化来提升启动性能。例如在旧架构中,为了向 JavaScript 暴露全局方法,我们需要在启动时初始化 JavaScript 模块,导致应用启动出现轻微延迟:

// ❌ Slow initialization
import {NativeTimingModule} from 'NativeTimingModule';
global.setTimeout = timer => {
NativeTimingModule.setTimeout(timer);
};

// App.js
setTimeout(() => {}, 100);

而新架构允许我们直接从 C++ 绑定方法:

// ✅ Initialize directly in C++
runtime.global().setProperty(runtime, "setTimeout", createTimer);
// App.js
setTimeout(() => {}, 100);

此次重写还改进了错误报告机制,特别是针对启动时的 JavaScript 崩溃,并减少了未定义行为导致的崩溃。若发生崩溃,新版 React Native DevTools 可简化调试流程并支持新架构。

桥接层目前仍保留以向后兼容,支持逐步迁移至新架构。未来我们将完全移除桥接层代码。

逐步迁移

我们预计大多数应用升级到 0.76 版本的工作量与常规版本更新相当。

当你升级到 0.76 时,新架构(New Architecture)和 React 18 将默认启用。然而,要使用并发功能(concurrent features)并充分发挥新架构的优势,你的应用和库需要逐步迁移以全面支持新架构。

首次升级时,你的应用将在新架构上运行,并自动启用与旧架构的互操作性层。对于大多数应用,这无需任何更改即可工作,但互操作层存在已知限制,因为它不支持访问自定义 Shadow Nodes 或并发功能。

要使用并发功能,应用还需要更新以支持并发式 React(Concurrent React),并遵循 React 规则。要将你的 JavaScript 代码迁移到 React 18 及其语义,请遵循 React 18 升级指南

整体策略是让你的应用在不破坏现有代码的前提下运行于新架构上。然后你可以按照自己的节奏逐步迁移应用。对于已将全部模块迁移到新架构的新界面(new surfaces),你可以立即开始使用并发功能。对于现有界面,你可能需要先解决一些问题并迁移模块,然后再添加并发功能。

我们已经与最受欢迎的 React Native 库合作,以确保对新架构的支持。目前已有超过 850 个库兼容新架构,这包括所有周下载量超过 20 万次的库(约占已下载库的 10%)。你可以在 reactnative.directory 网站上查看库对新架构的兼容性:

有关升级的更多详细信息,请参阅下方的如何升级

新功能

新架构全面支持 React 18、并发功能以及在 React Native 中使用 useLayoutEffect。有关 React 18 功能的完整列表,请参阅 React 18 博客文章

过渡(Transitions)

过渡(Transitions)是 React 18 中的一个新概念,用于区分紧急更新和非紧急更新。

  • 紧急更新(Urgent updates) 反映了直接交互,例如输入和按压。

  • 过渡更新(Transition updates) 将 UI 从一个视图转换到另一个视图。

紧急更新需要立即响应,以符合我们对物理对象行为的直觉。然而,过渡更新则不同,因为用户并不期望在屏幕上看到每一个中间值。在新架构中,React Native 能够分别渲染紧急更新和过渡更新。

通常,为了获得最佳用户体验,一次用户输入应同时触发紧急更新和非紧急更新。与 ReactDOM 类似,像 presschange 这样的事件会被视为紧急事件并立即渲染。你可以在输入事件中使用 startTransition API 来告知 React 哪些更新属于"过渡"更新,可以延迟到后台处理:

import {startTransition} from 'react';

// Urgent: Show the slider value
setCount(input);

// Mark any state updates inside as transitions
startTransition(() => {
// Transition: Show the results
setNumberOfTiles(input);
});

将紧急事件与过渡更新分开,可以实现更响应的用户界面和更直观的用户体验。

以下是没有过渡更新的旧架构与具有过渡更新的新架构的对比。假设每个图块并非仅具有背景色的简单视图,而是包含图像和其他渲染成本较高的组件的丰富组件。使用 useTransition ,你可以避免应用因更新而卡顿和掉队。

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.
Before: rendering tiles without marking it as a transition.
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.
After: rendering tiles with transitions to interrupt in-progress renders of stale state.

欲了解更多信息,请参阅支持并发渲染器与特性

自动批处理(Automatic Batching)

升级到新架构时,你将受益于 React 18 的自动批处理功能。

自动批处理允许 React 在渲染时将更多状态更新批量合并,避免渲染中间状态。这使得 React Native 运行更快、更不易卡顿,开发者无需编写额外代码即可实现。

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.
Before: 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.
After: rendering frequent state updates with automatic batching.

在旧架构中,会渲染更多中间状态,即使滑块停止移动 UI 仍持续更新。而新架构通过自动批处理更新,渲染的中间状态更少,并能更快完成渲染。

欲了解更多信息,请参阅支持并发渲染器与特性

useLayoutEffect

基于事件循环和同步读取布局的能力,我们在新架构中为 React Native 的 useLayoutEffect 提供了完善支持。

在旧架构中,必须使用异步的 onLayout 事件读取视图布局信息(同样异步)。这导致至少有一帧布局信息错误,直到布局被读取更新,造成诸如提示框位置错误等问题:

// ❌ async onLayout after commit
const onLayout = React.useCallback(event => {
// ❌ async callback to read layout
ref.current?.measureInWindow((x, y, width, height) => {
setPosition({x, y, width, height});
});
}, []);

// ...
<ViewWithTooltip
onLayout={onLayout}
ref={ref}
position={position}
/>;

新架构通过允许在 useLayoutEffect 中同步访问布局信息来解决此问题:

// ✅ sync layout effect during commit
useLayoutEffect(() => {
// ✅ sync call to read layout
const rect = ref.current?.getBoundingClientRect();
setPosition(rect);
}, []);

// ...
<ViewWithTooltip ref={ref} position={position} />;

此项更改允许您同步读取布局信息并在同一帧中更新 UI,从而在元素显示给用户之前正确放置它们:

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
In the old architecture, layout was read asynchronously in onLayout, causing the position of the tooltip to be delayed.
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.
In the New Architecture, layout can be read in useLayoutEffect synchronously, updating the tooltip position before displaying.

更多信息,请参阅文档中的同步布局与效果

对 Suspense 的完整支持

Suspense 允许你以声明式方式为尚未准备好的组件树部分指定加载状态:

<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>

我们数年前推出了功能有限的 Suspense 版本,React 18 增加了完整支持。但此前 React Native 一直无法支持 Suspense 的并发渲染。

新架构包含对 React 18 中 Suspense 的完整支持。现在你可以在 React Native 中使用 Suspense 处理组件加载状态,被暂停的内容将在后台渲染,同时显示加载状态,并对可见内容的用户输入给予更高优先级。

更多细节请参阅 React 18 的 Suspense RFC

如何升级

升级到 0.76 请遵循发布说明中的步骤。由于此版本同时升级到 React 18,你还需要遵循 React 18 升级指南

得益于与旧架构的互操作层,多数应用只需完成上述步骤即可升级。但要充分利用新架构并启用并发功能,你需要将自定义原生模块(Native Modules)和原生组件(Native Components)迁移至新 API。

若不迁移自定义原生模块,你将无法获得共享 C++、同步方法调用或代码生成的类型安全等优势。若不迁移原生组件,则无法使用并发功能。我们建议尽快迁移所有原生组件和原生模块。

备注

未来版本将移除互操作层,所有模块均需支持新架构。

应用开发者

应用开发者要完全支持新架构,需升级所有依赖库、自定义原生组件和自定义原生模块。

我们已与主流 React Native 库合作确保新架构兼容性,你可以在 reactnative.directory 网站查看库的兼容状态。

如果你的应用依赖的某些库尚未兼容新架构,可以采取以下措施:

  • 向库作者提交 issue,请求迁移至新架构

  • 如果该库已停止维护,可考虑功能相同的替代库

  • 暂时退出新架构,待依赖库完成迁移

如果你的应用包含自定义原生模块(Native Modules)或自定义原生组件(Native Components),得益于我们的互操作层,它们应该能正常工作。但我们建议尽快升级到新的原生模块和组件 API,以完全支持新架构并兼容并发特性。

请参考以下指南进行迁移:

库维护者指南

库维护者请先测试您的库在互操作层下的兼容性。如发现问题,请在新架构工作组提交 issue。

建议尽快将库迁移到新的原生模块和组件 API,这将使您的用户能充分利用新架构特性并支持并发渲染。

迁移指南参考:

退出新架构

若新架构在您的应用中表现异常,可随时退出新架构模式,待准备就绪后再重新启用。

退出方法:

  • 在 Android 平台上,请修改 android/gradle.properties 文件并关闭 newArchEnabled 标志:
-newArchEnabled=true
+newArchEnabled=false
  • iOS:运行以下命令重新安装依赖:
RCT_NEW_ARCH_ENABLED=0 bundle exec pod install

致谢

将新架构交付给开源社区是我们历时数年的重大工程。在此衷心感谢所有参与此项目的 React 团队现任及前任成员。

同时特别鸣谢以下合作伙伴:

  • Expo:率先采用新架构,并协助迁移主流库

  • Software Mansion:维护关键生态库,早期完成迁移,并协助排查修复各类问题

  • Callstack:维护关键生态库,早期完成迁移,并协助社区 CLI 开发

  • Microsoft:为 react-native-windowsreact-native-macos 实现新架构,并贡献多项开发工具

  • ExpensifyKrakenBlueskyBrigad:作为新架构先行者,反馈各类问题使整个社区受益

  • 所有独立库维护者和开发者,他们通过测试新架构、修复部分问题以及就未明确之处提出问题以便我们澄清,为新架构做出了贡献。