跳到主要内容

React Native 0.75 - 支持布局中的百分比值、新架构稳定化、模板和初始化更新等

·阅读16分钟
Gabriel Donadel Dall'Agnol
Gabriel Donadel Dall'Agnol
Expo 软件工程师
Siddharth Kulkarni
Siddharth Kulkarni
Coinbase 软件工程师
Thibault Malbranche
蒂博·马尔布朗什
Brigad 首席移动工程师
Blake Friedman
Blake Friedman
Meta 软件工程师
Riccardo Cipolleschi
Riccardo Cipolleschi
Meta 软件工程师
Nicola Corti
Nicola Corti
Meta 软件工程师

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

此版本带来了多项功能,例如支持百分比值的 Yoga 3.1、多项新架构的稳定性修复,以及向用户推荐使用 React Native 框架。

亮点

破坏性变更

亮点

Yoga 3.1 和布局改进

自从我们上次在 React Native 0.74 中发布 Yoga 3.0 版本以来,我们不断为您的应用程序推出许多改进和新的布局功能。React Native 0.75 附带 Yoga 3.1,您可以在 Yoga 官方发布博客文章中了解更多新内容。

一个值得注意且备受期待的功能是支持在各种位置使用 % 值,例如 gapstranslation

信息

这些功能仅适用于新架构。如果您想使用它们,请考虑迁移。

Gaps 中的百分比值

在 0.75 中,此处描述的 gapcolumnGaprowGap 属性现在支持带有 % 值的字符串。

例如

function App(): React.JSX.Element {
return (
<SafeAreaView
style={{
marginTop: 20,
alignItems: 'center',
flex: 1,
rowGap: '20%',
}}>
<View
style={{flex: 1, flexDirection: 'row', columnGap: '10%'}}>
<View
style={{
backgroundColor: 'purple',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'blue',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'green',
width: 100,
height: 100,
}}
/>
</View>
<View
style={{flex: 1, flexDirection: 'row', columnGap: '10%'}}>
<View
style={{
backgroundColor: 'lime',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'yellow',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'orange',
width: 100,
height: 100,
}}
/>
</View>
<View
style={{flex: 1, flexDirection: 'row', columnGap: '10%'}}>
<View
style={{
backgroundColor: 'red',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'violet',
width: 100,
height: 100,
}}
/>
<View
style={{
backgroundColor: 'magenta',
width: 100,
height: 100,
}}
/>
</View>
</SafeAreaView>
);
}

将渲染如下

AndroidiOS
Android GapsiOS Gaps

Translation 中的百分比值

transform 属性现在也可以接受 % 作为 translate 转换的值。

例如,以下组件将使红色正方形的 X 坐标移动其宽度的 100%,Y 坐标移动其高度的 100%。

function Translated() {
return (
<SafeAreaView
style={{
marginTop: 20,
flex: 1,
rowGap: '20%',
}}>
<View
style={{
backgroundColor: 'red',
width: 100,
height: 100,
transform: [{translateY: '100%'}, {translateX: '100%'}],
}}
/>
</SafeAreaView>
);
}

将渲染如下

AndroidiOS
Android TranslationiOS Translation

新架构稳定

自我们在 React Conf 上宣布新架构处于 Beta 阶段以来,我们已经发布了多个错误修复和稳定性改进。

我们的目标是让新架构在不久的将来被认为是稳定的。因此,在过去几个月,我们专注于弥合旧架构和新架构之间的差距。我们修复的一些错误和缺失功能示例包括:

  • 修复 Android 上的 adjustsFontSizeToFit (#44075)
  • 修复 Android 上 textAlign 不适用于内联视图的问题 (#44146)
  • 修复 iOS 上文本基线向上移动的问题 (#44932)

我们还与 Expo 的伙伴合作,在 React Native Directory 中添加了有关新架构支持的信息,这样您就可以立即清楚地知道一个库是否已经支持新架构。

React Native Directory

我们还邀请您参与新架构调查。这项调查对我们收集有关新架构推广下一步的宝贵反馈至关重要。

我们还想分享一篇在新架构工作组中发布的关于在新架构中支持 UIManager 的帖子。这篇文章提供了 Android 上 UIManager API 的概述,以及它如何帮助更高级的应用程序和库进行迁移。

此版本还包含一个新的 API,现在是访问 jsi::Runtime 的推荐方式。

在 TurboModules 中访问 jsi::Runtime

过去,从未有推荐的本地模块访问 jsi::Runtime 的方法,消费者会冒风险绕过框架进行操作。在 0.74 中,我们引入了实验性 API,提供了对 jsi::Runtime 的安全访问,我们很高兴地宣布它们在 0.75 中已稳定。

如何访问 jsi::Runtime 的示例

在 iOS 上,您可以让您的 Turbo Native Module 遵循 RCTTurboModuleWithJSIBindings 协议。您现在可以实现 installJSIBindingsWithRuntime,它将为您提供对运行时的线程安全访问。

@interface RCTSampleTurbo Module () <RCTTurboModuleWithJSIBindings>
@end

#pragma mark - RCTTurboModuleWithJSIBindings
- (void)installJSIBindingsWithRuntime:(jsi::Runtime &)runtime {
runtime.global().setProperty(
runtime,
"myGlobalFunction",
jsi:: Function::createFromHost Function(...));
}

在 Android 上,您可以让您的 Turbo Native Module 遵循 TurboModuleWithBindings 接口。您现在可以实现 JNI 方法 getBindingsInstaller,它将为您提供在 C++ 中对运行时的线程安全访问。

public class SampleTurboModule extends NativeSampleTurboModuleSpec implements TurboModuleWithJSIBindings

@Override
public native BindingsInstallerHolder getBindingsInstaller();
// C++
jni::local_ref<BindingsInstallerHolder::javaobject> SampleTurboModuleJSIBindings::getBindingsInstaller(jni::alias_ref<jni::object> jobj) {
return BindingsInstallerHolder::newObjectCxxArgs(
[](jsi::Runtime& runtime) {
runtime.global().setProperty(
runtime,
“myGlobalFunction”,
jsi::Function::createFromHostFunction(...));
}
);
}

如果您在 UI 线程上需要访问运行时,我们引入了一个新的 API:CallInvoker。它包含一个方法 invokeAsync,它将跳到 JS 线程,以使用 JS 运行时安全地执行一些工作。这些 API 是向前兼容的。

在 iOS 上,我们提供了 RCTCallInvokerModule 协议。在遵循此协议后,我们的基础设施将使用 CallInvoker 访问权限来装饰模块。

@interface RCTSampleTurboModule() <RCTCallInvokerModule>

[self.callInvoker callInvoker].invokeAsync([&](jsi::Runtime& runtime) {
// do stuff on JS thread
}

在 Android 上,CallInvoker 可以通过 ReactContext 中的 JNI 包装器 CallInvokerHolder 访问,然后您可以在跨越 JNI 边界后调用 invokeAsync

// Java
public abstract CallInvokerHolder getJSCallInvokerHolder();
// C++
jsCallInvokerHolder->cthis()->getCallInvoker()->invokeAsync([&](jsi::Runtime& rt) {
// do stuff on JS thread
});

使用框架

正如我们今年早些时候在 React Conf 上分享的,构建 React Native 应用程序的推荐方式现在是通过框架,例如 Expo。

您可以在我们之前的博客文章中阅读更多关于此指南的信息:《使用框架构建 React Native 应用程序》。

我们希望帮助新的 React Native 用户取得成功。我们相信使用框架能让您尽可能高效,并在构建新应用程序时提供最佳的开发者体验。

为了反映这些建议,此版本包含以下更改:

  • 我们将 /template 文件夹从 react-native 包移至一个单独的仓库:react-native-community/template
  • 我们将于 2024 年 12 月 31 日停止支持 react-native init 命令。

如果您已经在使用像 Expo 这样的框架,这些更改将完全不会影响您。您可以将 React Native 0.75 与 Expo SDK 51 一起使用(您可以在这篇专门的 Expo 文章中找到操作说明)。

如果您不使用框架或正在构建自己的框架,让我们看看这些更改将如何影响您。

将模板移动到 react-native-community/template

从历史上看,react-native 过去在 NPM 包中附带一个 /template 文件夹,社区 CLI 使用它来创建新项目。这使得模板更新变得相当缓慢,因为每次模板更改都需要新的 React Native 版本。

鉴于我们最新的推荐是使用框架,我们认为在我们的核心 NPM 包中发布一个带有主观判断的模板与我们的愿景不符。

因此,我们决定将模板移至 @react-native-community/template 包。

这将使社区更容易维护和发展模板,而无需为每个更改依赖 React Native 发布。此外,这将使模板更接近社区 CLI,并使所有人更容易将模板作为单独的包进行检查和依赖。

对于使用 Community CLI 创建新项目的用户来说,此更改应该是完全透明的。从现在开始,与模板相关的新问题应在模板问题跟踪器上报告。所有依赖模板的各种工具,例如升级助手,也已相应更新,并将继续正常工作。

逐步淘汰 react-native init

与模板类似,react-native init 命令也进行了调整,以与新的推荐保持一致。

从历史上看,react-native init 是创建新的 React Native 项目的默认命令。然而,在 2024 年,我们认为此命令无法提供框架所能提供的相同入门体验。这就是为什么我们不再推荐它,而是建议您使用像 Expo 这样的框架。

您今天仍然可以使用 react-native init 通过 Community CLI 和模板创建新项目,但您会看到以下警告:

Init Deprecation

从 2024 年 12 月 31 日起,init 命令将不再创建项目。您将必须选择:

  • 使用像 Expo 这样的框架,它有自己专门的命令来创建新项目,例如 npx create-expo-app
  • 直接使用 npx @react-native-community/cli init 调用 Community CLI。

请注意,react-native config 和除 init 之外的所有其他命令将继续正常工作。

信息

为了提供更顺畅的迁移体验,react-native@0.75.0 包仍然依赖于 @react-native-community/cli,但我们计划在不久的将来移除此依赖项。

自动链接性能改进

在更新 init 命令的过程中,我们还花费时间重写了自动链接逻辑,以提高性能。这使得 Android 和 iOS 的构建速度更快。

使用 React Native 0.75,如果您使用 Expo,自动链接步骤现在在 Android 上可以快约 6.5 倍,在 iOS 上快约 1.5 倍。您可以在此处阅读更多关于这些改进的信息。

重大变更

虽然即将到来的这一部分看起来很长,但我们预计这里的重大更改主要会影响少数以更高级方式使用 React Native 的用户。

为了完整性和参考起见,我们在此处列出它们。

TypeScript 中的可触摸组件不能再用作泛型表达式中的类型

TouchablesOpacityTouchableHighlights 组件已转换为函数式组件。这意味着它们不能再用作 value & type。因此,例如,以下代码不再有效:

import {TouchableHighlight} from 'react-native';
const ref = useRef<TouchableHighlight>();
// ^^^ TS2749: TouchableHighlight refers to a value, but is being used as a type here.
// Did you mean typeof TouchableHighlight?

相反,您应该使用内置的 React 类型 React.ElementRef,或者,也可以使用 View 类型。

import {TouchableHighlight} from 'react-native';
const ref1 =
useRef<React.ElementRef<typeof TouchableHighlight>>();
// or
const ref2 = useRef<View>();

支持 minSdk 23 和 minIOSVersion 13.4 的最后一个版本

这些并非 0.75 中的重大更改,但我们想分享的是,React Native 0.75 将是支持 minSdk 23 (Android 6.0) 和 minIOSVersion 13.4 的最后一个 React Native 版本。

从 React Native 0.76 开始,minSdk 版本将是 24 (Android 7.0),minIOSVersion 将是 15.1。

您可以在我们关于AndroidiOS的官方公告中阅读更多信息。

Android: JSIModule 已被删除

com.facebook.react.bridge.JSIModule (来源) 是我们临时引入的一个 API,允许 Native Module 直接访问 Android 上的 JSI。此 API 的访问器在 0.74 中已弃用,我们验证了此 API 在开源中没有有意义的使用,因此我们在 0.75 中将其删除。您可以改用Turbo Native Modules 作为替代。

Android:弹出菜单已移至单独的包中

在 0.74 中,我们将 Android 的 PopUpMenu 移动到 @react-native 范围下的一个单独包中。在 0.75 中,我们正在移除核心中仍然存在的剩余方法:

  • UIManagerModule.showPopupMenu()
  • UIManagerModule.dismissPopupMenu()

作为替代方案,请使用 @react-native/popup-menu-android 包中的 <PopupMenuAndroid /> 组件。

iOS:PushNotificationIOS 废弃工作已完成

在 0.74 中,我们废弃PushNotificationIOS 模块的一些 API。

在 0.75 中,我们已删除这些 API,以摆脱旧式的通知元数据表示。

已删除的 API 如下:

  + (void)didReceiveLocalNotification:(UILocalNotification *)notification;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;

改为使用 didReceiveNotification:(UNNotification *)notification

社区 CLI:移除 ram-bundle 和 profile-hermes 命令

我们想宣布社区 CLI 即将移除的两个重要命令:ram-bundleprofile-hermes

ram-bundle 命令在 React Native 0.59 中引入,允许您通过直接在内存中加载 bundles 来运行它们。此功能现在已被我们的默认 JS 引擎 Hermes 取代。您不应再使用 ram-bundle 命令。

profile-hermes 命令是一个帮助您分析 JavaScript 代码 CPU 性能的工具。它使用旧的 .cpuprofile 格式,该格式在最新版本的 Chrome 中不再受支持。将其作为一个独立命令包含在内也是我们正在放弃的做法,因为我们正在努力提高调试工具的质量标准。现在可以通过实验性新调试器中的“Profiler”面板访问 CPU 分析(注意:如果从 Chrome 连接到 Hermes,则无法访问)。

其他重大变更

通用

  • 代码生成
    • 纯 C++ TurboModules 生成的类和结构体名称略有改变。我们从其名称中删除了 Cxx 标记。
    • 由于可能出现精度误差,浮点枚举不再受支持。
    • 当在 JS 中将 null 传递给 Native 中的不可为空参数时,将抛出错误。
  • 代码检查
    • ESLint 配置在 linting 时不再运行 prettier。
  • C++
    • ScrollViewShadowNode 现在在构造函数中需要一个新的 bool includeTransform 参数。
    • 从 RuntimeExecutor 中移除 executeAsynchronouslyexecuteSynchronously_CAN_DEADLOCK
    • JsErrorHandler.h 中将 JsErrorHandlingFunc 重命名为 OnJsError
    • handleFatalError.h 中将 handleJsError 重命名为 OnJsError
    • 删除 ReactPrimitives.h 中未使用的 import
    • LongLivedObjectCollectionLongLivedObject 的 get 方法现在接受一个 Runtime 参数。
    • utils/jsi.h 文件重命名为 jsi-utils.h
  • 文本输入
    • 移除已弃用的 onTextInput 回调。
  • 可按性
    • 移除了 onLongPressShouldCancelPress_DEPRECATEDonResponderTerminationRequest_DEPRECATEDonStartShouldSetResponder_DEPRECATED 方法。

Android

  • ReactViewBackgroundDrawable
    • 已弃用,建议使用 CSSBackgroundDrawable。这也从 ReactViewBackgroundDrawableColorUtil 中移除了一些 API。
  • ReactContext
    • ReactContextReactApplicationContext 现在是抽象的。请改用 BridgeReactContextBridgelessReactContext
    • 删除 ReactContext.initializeWithInstance()。请改用 BridgeReactInstance
    • BridgelessReactContext.getJavaScriptContextHolder() 中删除。请改用 BridgelessCatalystInstance
    • 删除 ReactContext.getRuntimeExecutor()。请使用 BridgelessCatalystInstance
  • 布局
    • 支持百分比弹性间距值。这将 setGapsetRowGapsetColumnGap 等方法的参数从浮点数更改为动态类型。
    • Android Manifest 中需要 supportsRTL
  • 运行时
    • 从 ReactHostImpl 中移除 ReactJsExceptionHandler
    • 如果未使用默认模板,则由应用程序负责返回核心 turbomodules。
  • 开发支持
    • DevSupportManagerFactory.create() 更改为接受新的 PausedInDebuggerOverlayManager 参数。
  • 测量
    • 已删除 UIManagerModule.measureLayoutRelativeToParent()

iOS

  • 运行时
    • 移除 [RCTHost getSurfacePresenter][RCTHost getModuleRegistry]
    • 移除 EventPriority 类,并始终使用默认的 EventPriority::AsynchronousBatched。如果构建失败,请移除所有 EventPriority 的使用。
  • 图像
    • 移除未使用的 RCTImageLoadingPerfInstrumentationEnabled
  • 错误处理
    • 通过 RCTBridge 移除 RCTRedBox 访问。
  • CocoaPods
    • BUILD_FROM_SOURCE 重命名为 RCT_BUILD_HERMES_FROM_SOURCE
    • 为更好地兼容 use_frameworks 和 Swift,将 React-Codegen 重命名为 ReactCodegen
  • 文本输入
    • 移除已弃用的 onTextInput 回调。

致谢

React Native 0.75 包含了来自 165 位贡献者的超过 1491 次提交。感谢大家的辛勤工作!

感谢所有为本版本发布文章撰写文档的额外作者

升级到 0.75

请使用 React Native 升级助手来查看现有项目 React Native 版本之间的代码更改,以及升级文档。

要创建新项目

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

如果您使用 Expo,Expo SDK 51 将支持 React Native 0.75(有关如何将 Expo 项目中的 React Native 更新到 0.75.0 的说明可在此专用文章中找到)。

信息

0.75 现在是 React Native 的最新稳定版本,0.72.x 不再受支持。有关更多信息,请参阅React Native 的支持政策。我们计划在不久的将来发布 0.72 的最终终止支持更新。