React Native 0.75 - 布局支持百分比值、新架构稳定化、模板与初始化更新等
今天我们很高兴发布 React Native 0.75!
此版本包含多项功能,例如支持 `%` 值的 Yoga 3.1、新架构的多项稳定性修复,以及引入推荐用户使用 React Native 框架的建议。
亮点
重大变更
- TypeScript 中的 Touchables 不能再用作泛型表达式中的类型
- 支持 minSdk 23 和 minIOSVersion 13.4 的最后一个版本
- Android:JSIModule 已删除
- Android:弹出菜单已从核心库中移除
- iOS:推送通知弃用工作已完成
- 社区 CLI:移除 ram-bundle 和 profile-hermes 命令
亮点
Yoga 3.1 和布局改进
自我们在 React Native 0.74 中发布 Yoga 3.0 版本以来,我们一直在为您的应用程序推出许多改进和新的布局功能。React Native 0.75 附带 Yoga 3.1,您可以在 Yoga 官方发布博客文章中了解更多新内容。
一个值得注意且备受期待的功能是支持在各种地方使用 `%` 值,例如 `gaps` 和 `translation`
这些功能仅适用于新架构。如果您热衷于使用它们,请考虑迁移到新架构。
Gaps 中的百分比值
在 0.75 版本中,此处描述的 `gap`、`columnGap` 和 `rowGap` 属性现在支持带有 `%` 值的字符串。
例如
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>
);
}
将渲染如下
Android | iOS |
---|---|
![]() | ![]() |
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>
);
}
将渲染如下
Android | iOS |
---|---|
![]() | ![]() |
新架构稳定化
自我们在 React Conf 上宣布新架构处于 Beta 阶段以来,我们发布了多项错误修复和稳定性改进。
我们的目标是让新架构在不久的将来被认为是稳定的。因此,在过去几个月里,我们专注于弥合旧架构和新架构之间的差距。我们修复的一些错误和缺失功能示例如下:
- 修复 Android 上
adjustsFontSizeToFit
的问题 (#44075) - 修复 Android 上
textAlign
在内联视图中不起作用的问题 (#44146) - 修复 iOS 上文本基线向上移动的问题 (#44932)
我们还与 Expo 的同事们合作,在 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 原生模块符合 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 原生模块符合 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 上,可以通过 ReactContext
中的一个名为 CallInvokerHolder
的 JNI 包装器访问 CallInvoker
,您可以在跨越 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,并将使每个人更容易将模板作为独立包进行检查和依赖。
对于使用社区 CLI 创建新项目的用户来说,此更改应该是完全透明的。从现在开始,与模板相关的新问题应在模板问题追踪器上报告。所有依赖于模板的各种工具,如升级助手,也已相应更新,并将继续正常工作。
停止支持 react-native init
与模板类似,react-native init
命令也进行了调整,以符合新的建议。
历史上,react-native init
是创建新 React Native 项目的默认命令。然而,在 2024 年,我们认为此命令无法提供框架所能提供的相同入门体验。这就是我们不再推荐它的原因,相反,您应该使用像 Expo 这样的框架。
您今天仍然可以使用 react-native init
通过社区 CLI 和模板创建新项目,但您会看到以下警告
从 2024 年 12 月 31 日起,init
命令将不再创建项目。您将不得不选择以下方式之一:
- 使用像 Expo 这样的框架,它有自己专门的命令来创建新项目,例如
npx create-expo-app
- 直接使用
npx @react-native-community/cli init
调用社区 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 中的 Touchables 不能再用作泛型表达式中的类型
TouchablesOpacity
和 TouchableHighlights
组件已转换为函数式组件。这意味着它们不能再用作 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 将是 React Native 支持 minSdk 23 (Android 6.0) 和 minIOSVersion 13.4 的最后一个版本。
从 React Native 0.76 开始,minSdk 版本将是 24 (Android 7.0),minIOSVersion 将是 15.1。
您可以在我们针对Android和iOS的官方公告中阅读更多相关信息。
Android:JSIModule 已删除
com.facebook.react.bridge.JSIModule
(源代码) 是我们临时引入的一个 API,允许原生模块直接在 Android 上访问 JSI。此 API 的访问器在 0.74 中已弃用,我们验证了在开源中没有有意义地使用此 API,因此我们将在 0.75 中将其移除。作为替代方案,您可以使用Turbo 原生模块。
Android:弹出菜单已移动到单独的包
在 0.74 中,我们将 Android 的 PopUpMenu
移动到了 @react-native
范围下的一个单独包中。在 0.75 中,我们正在移除核心库中剩余的方法:
UIManagerModule.showPopupMenu()
UIManagerModule.dismissPopupMenu()
作为替代方案,请使用 <PopupMenuAndroid />
组件,它位于 @react-native/popup-menu-android
包中。
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-bundle
和 profile-hermes
。
ram-bundle
命令在 React Native 0.59 中引入,允许您通过直接在内存中加载捆绑包来运行它们。此功能现在已被我们的默认 JS 引擎 Hermes 取代。您不应再使用 ram-bundle
命令。
profile-hermes
命令是一个帮助您分析 JavaScript 代码 CPU 性能的工具。它使用旧的 .cpuprofile
格式,此格式在最新版本的 Chrome 中不再受支持。将此功能作为独立命令也正在被我们放弃,因为我们致力于提高调试工具的质量标准。现在可以通过实验性新调试器中的“Profiler”面板访问 CPU 分析(注意:如果从 Chrome 连接到 Hermes,则无法访问此功能)。
其他重大变更
一般
- 代码生成
- 轻微更改了纯 C++ TurboModules 生成的类和结构体的名称。我们从它们的名称中去掉了
Cxx
标记 - 由于可能存在的精度误差,浮点枚举不再受支持
- 当在 JS 中将
null
传递给原生代码中不可为空的参数时抛出错误
- 轻微更改了纯 C++ TurboModules 生成的类和结构体的名称。我们从它们的名称中去掉了
- 代码检查
- ESLint 配置在代码检查时不再运行 Prettier
- C++
ScrollViewShadowNode
现在在构造函数中需要一个新的bool includeTransform
参数- 从 RuntimeExecutor 中移除了
executeAsynchronously
和executeSynchronously_CAN_DEADLOCK
- 在
JsErrorHandler.h
中将JsErrorHandlingFunc
重命名为OnJsError
- 在
handleFatalError.h
中将handleJsError
重命名为OnJsError
- 从
ReactPrimitives.h
中移除了未使用的import
LongLivedObjectCollection
和LongLivedObject
的 get 方法现在接受一个 Runtime 参数- 将
utils/jsi.h
文件重命名为jsi-utils.h
- 文本输入
- 移除了已弃用的
onTextInput
回调
- 移除了已弃用的
- 可按压性
- 移除了
onLongPressShouldCancelPress_DEPRECATED
、onResponderTerminationRequest_DEPRECATED
和onStartShouldSetResponder_DEPRECATED
方法
- 移除了
Android
- ReactViewBackgroundDrawable
- 已弃用,转而使用
CSSBackgroundDrawable
。这也从ReactViewBackgroundDrawable
和ColorUtil
中移除了一些 API
- 已弃用,转而使用
- ReactContext
ReactContext
和ReactApplicationContext
现在是抽象类。请改用BridgeReactContext
和BridgelessReactContext
- 删除
ReactContext.initializeWithInstance()
。请改用BridgeReactInstance
- 移除
BridgelessReactContext.getJavaScriptContextHolder()
。请改用BridgelessCatalystInstance
- 移除
ReactContext.getRuntimeExecutor()
。请改用BridgelessCatalystInstance
- 布局
- 支持百分比 flex gap 值。这会将
setGap
、setRowGap
和setColumnGap
等一些方法的参数从 float 更改为 dynamic - Android Manifest 中需要
supportsRTL
- 支持百分比 flex gap 值。这会将
- 运行时
- 从 ReactHostImpl 中移除了
ReactJsExceptionHandler
- 当不使用默认模板时,应用程序负责返回核心 turbomodule
- 从 ReactHostImpl 中移除了
- 开发支持
- 将
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
- 将
React-Codegen
重命名为ReactCodegen
,以更好地兼容use_frameworks
和 Swift
- 将
- 文本输入
- 移除已弃用的
onTextInput
回调
- 移除已弃用的
致谢
React Native 0.75 包含了来自 165 位贡献者的超过 1491 次提交。感谢您的辛勤工作!
感谢所有参与撰写此发布文章中功能文档的额外作者
- Nick Gerleman 和 Joe Vilches 贡献了 Yoga 3.1 和布局改进
- Arushi Kesarwani 贡献了新架构中对 UIManager 的支持
- Phillip Pan 贡献了在 TurboModules 中访问 jsi::Runtime
- Alan Lee 和 Soe Lynn 贡献了支持 minSdk 23 和 minIOSVersion 13.4 的最后一个版本
- Kudo Chien 贡献了自动链接性能改进
- Alex Hunt 贡献了移除
ram-bundle
和profile-hermes
命令
升级到 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 的最终生命周期结束更新。