跳到主要内容

React Native 0.78 - React 19 及更多内容

· 阅读需 10 分钟
Vojtech Novak
Vojtech Novak
Software Engineer @ Expo
Shubham Gupta
Shubham Gupta
Software Engineer @ Dream11
Fabrizio Cucci
Fabrizio Cucci
Software Engineer @ Meta
Riccardo Cipolleschi
Riccardo Cipolleschi
Software Engineer @ Meta

今天我们很高兴发布 React Native 0.78!

本次发布在 React Native 中引入了 React 19 以及一些其他相关功能,例如原生支持 Android 矢量图片(Vector drawables)和 iOS 更好的棕地集成(brownfield integration)。

亮点

亮点

React 19

React 19 现已可在 React Native 中使用!

React 19 需要你更新你的应用,因为与 React 18 相比引入了一些变更。例如,我们移除了一些 API,比如 propTypes,你需要调整应用以兼容 React 的新版本。

请按照我们的分步升级指南将你的应用升级到 React 19。

迁移后,你将能够利用 React 的所有新特性,包括但不限于:

  • Actions 这是使用异步过渡(async transitions)的函数。异步过渡能自动帮助你管理数据提交,处理挂起状态、乐观更新、错误处理等。
  • useActionState 基于 Actions 构建的实用 Hook。接收一个函数并返回一个封装好的 Action 调用。当调用该 Action 时,会返回最近一次的结果及其 pending 状态。
  • useOptimistic 一个新的 Hook,可简化在异步请求进行时以乐观方式显示最终更新状态。如果请求失败,React 会自动回退到之前的值。
  • use 全新的 API,允许在渲染期间访问资源。你现在可以使用 use 读取 Promise 或 Context,React 会 Suspend(挂起)等待它们解析。
  • ref 作为 props 你现在可以像传递其他 props 一样传递 ref。函数式组件不再需要 forwardRef,你可以立即迁移组件。
  • 以及更多其他功能

完整的新功能列表,请参见 React 19 发布博客

React 编译器

React 编译器是一个构建时工具,旨在通过自动应用记忆化优化 React 应用。虽然开发者可以手动使用 useMemouseCallbackReact.memo 等 API 避免不必要的重新计算,但也可能会忘记或误用这些优化。React 编译器通过理解 JavaScript 及 React 规则,自动为组件和 Hooks 中的值或值组进行记忆化。

本次发布简化了在 React Native 应用中启用 React 编译器的流程。之前版本需要安装两个包:编译器和运行时。安装后还需配置 Babel 插件才能通过 Metro 启用 React 编译器。

现在,只需安装编译器本身并配置 Babel 插件即可。想了解如何启用,请参阅我们的分步指南

可通过打开 React Native DevTools 验证编译器是否运行:在组件检查器中,已记忆化的组件上应显示 Memo ✨ 标签。

如想深入了解 React 编译器,可参考以下资料:

迈向更小更快的发布

我们正在更新发布流程,计划在 2025 年更频繁地发布稳定版 React Native。

这将让你更容易更新 React Native 版本,因为我们会减少引入破坏性变更的数量。更快的发布也意味着我们内部修复的所有 Bug 能更快到达你手中,你还能更早享受我们在 React Native 中开发的最新功能。

我们相信此新模型将惠及 React Native 生态的每一位开发者,更少的破坏性变更意味着更稳定的框架,更值得信赖。

Metro 中的 JavaScript 日志可选择开启

我们新增了一个可选开启选项,以恢复通过 Metro 开发服务器流式传输 JavaScript 日志的功能,之前版本 0.77 中已为社区 CLI 用户移除该功能(详情见 0.77 版本更新)。此举响应了用户反馈,并基于我们对替代方案现状的评估。

要启用该功能,请使用新的 --client-logs 标志。也可以通过 npm 脚本别名方便使用。

npx @react-native-community/cli start --client-logs

Metro 中的日志流功能将来仍会被移除,且默认关闭。然而,我们计划给予开发者更长的迁移期以适应这一变更。

此更新也将发布于即将到来的 0.77.1 小版本中。

新增对 Android XML drawable 的支持

在 React Native 0.78 中,我们提供了在 Android 上以 XML 资源 方式加载图标、插图及其它图形元素的新方式。这意味着你可以使用 矢量 drawable 来无损缩放显示矢量图,或使用 形状 drawable 用于绘制基础装饰。这一切均由你熟悉的 Image 组件支持。要使用此功能,你可像引用任何其他静态资源一样,在 source 属性中引用 XML 资源。同时,使用 XML 资源代替位图有助于减小应用大小,并能在不同 DPI 的屏幕上获得更好渲染效果。

// 通过 require 引入
<Image
source={require('./img/my_icon.xml')}
style={{width: 40, height: 40}}
/>;

// 或通过 import 引入
import MyIcon from './img/my_icon.xml';
<Image source={MyIcon} style={{width: 40, height: 40}} />;

性能与质量

与其他图片类型相同,Android XML 资源的加载和解析均在主线程之外执行,因此不会掉帧。这意味着资源不会立即显示,但不会阻塞用户输入。线程外解码在需要同时渲染许多图标时尤为重要。内部应用在使用 Android 矢量 drawable 时实现了显著的性能提升。

使用矢量 drawable 等资源类型可以完美展示无损图像,且可显著减小 APK 文件,因为无需针对每个屏幕密度包含不同图片。此外,矢量 drawable 加载后会复制一次至内存,因此多次渲染同一图标时都能即时显示。

权衡

需要注意的是,drawable XML 资源不是完美无缺,且存在以下限制:

  • 必须在 Android 应用构建时被引用。这些资源会经过 Android 资源打包工具(AAPT)转换成二进制 XML。Android 不支持加载原始 XML 文件,这是已知限制
  • Metro 无法通过网络加载它们。如果更改 XML 资源的目录或名称,需要每次重新构建 Android 应用。
  • 不包含尺寸信息。默认显示为 0x0 大小,你需要指定宽高才能显示。
  • 运行时无法完全定制;只能控制尺寸和整体着色(tint color),但无法定制资源内部各个元素的属性,如描边宽度、边角半径或颜色。这类定制需要准备不同变体的 XML 资源。
信息

Android 的矢量 drawable 不能完全替代像 react-native-svg 这样的库。它们是专为 Android 设计,iOS 不支持。如果你想在所有平台保持相同的 SVG 文件,仍需使用 react-native-svg。矢量 drawable 的优势在于性能,但代价是定制性较低。

iOS 上的 ReactNativeFactory

React Native 0.78 改进了 iOS 上的集成体验。

该版本引入了一个新类 RCTReactNativeFactory,允许你无需 AppDelegate 即可创建 React Native 实例。例如,你可以在 ViewController 中直接创建一个 React Native 视图,大大简化了与棕地应用的集成。

假设你想在应用的某个 View Controller 中展示 React Native 视图。从 0.78 开始,完成此指南中的依赖安装后,只需要添加如下代码:


+import React
+import React_RCTAppDelegate

public class ViewController {

+ var reactNativeFactory: RCTReactNativeFactory?
+ var reactNativeDelegate: ReactNativeDelegate?

public func viewdidLoad() {
super.viewDidLoad()
// …
+ reactNativeDelegate = ReactNativeDelegate()
+ reactNativeFactory = RCTReactNativeFactory(delegate: reactNativeDelegate!)
+ view = reactNativeFactory.rootViewFactory.view(withModuleName: "<your module name>")
}

}

+class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {

+ override func sourceURL(for bridge: RCTBridge) -> URL? {
+ self.bundleURL()
+ }
+
+ override func bundleURL() -> URL? {
+ #if DEBUG
+ RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
+ #else
+ Bundle.main.url(forResource: "main", withExtension: "jsbundle")
+ #endif
+ }
+}

只要你跳转到该 View Controller,React Native 就会被加载。

这段代码创建了一个 RCTReactNativeFactory,赋予了它一个代理,并请求它根据 React Native 模块名称创建一个 rootView。

代理类定义在下方,重写了 sourceURLbundleURL 方法,告诉 React Native 从哪里加载 JS bundle。

其他破坏性变更

通用

  • React Native DevTools
    • 移除了 FuseboxClient CDP 域
  • Codegen
    • 区分组件数组类型与命令数组类型

Android

  • 可空性变更:因将 RootView 迁移至 Kotlin,参数类型由可空变为非可空。
  • 以下类已由公共变为内部或被移除,无法访问:
    • com.facebook.react.bridge.GuardedResultAsyncTask
    • com.facebook.react.uimanager.ComponentNameResolver
    • com.facebook.react.uimanager.FabricViewStateManager
    • com.facebook.react.views.text.frescosupport.FrescoBasedReactTextInlineImageViewManager

iOS

  • 修改 Image 加载事件中的尺寸信息,由逻辑尺寸改为像素(仅影响旧架构)

致谢

React Native 0.78 包含了来自 87 位贡献者的 509+ 次提交。感谢大家的辛勤付出!

感谢以下额外作者为本次发布文档的撰写所做的贡献:

升级到 0.78

请使用 React Native Upgrade Helper 来查看当前项目中不同 React Native 版本间的代码变动,搭配官方升级文档使用。

创建新项目:

npx @react-native-community/cli@latest init MyProject --version latest

若使用 Expo,React Native 0.78 将支持 Expo SDK 试验版

信息

0.78 现为 React Native 的最新稳定版本,0.75.x 将进入不再支持状态。更多详情请参阅 React Native 支持政策。我们计划在近期发布 0.75 的最终生命周期结束版本更新。