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
这些功能仅适用于新架构。如果您热衷于使用它们,请考虑迁移到新架构。
间隙中的百分比值
在 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 |
---|---|
平移中的百分比值
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 目录 中添加了有关新架构支持的信息,以便您可以立即了解某个库是否已支持新架构。
我们还邀请您参与 新架构调查。这项调查对于我们收集有关新架构推广下一步计划的宝贵反馈至关重要。
我们还希望分享我们在新架构工作组中发布的一篇关于 在新架构中支持 UIManager 的帖子。这篇文章提供了 Android 上 UIManager
API 的概述,以及它如何帮助更高级的应用和库的迁移。
此版本还包含一个新的 API,它现在是访问 jsi::Runtime
的首选方法。
在 TurboModules 中访问 jsi::Runtime
过去,原生模块从未有过访问 jsi::Runtime
的推荐方法,用户会以风险较高的方式绕过框架来实现此目的。在 0.74 中,我们引入了提供对 jsi::Runtime
安全访问的实验性 API,我们很高兴地宣布它们在 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 上,CallInvoker
通过 ReactContext
在名为 CallInvokerHolder
的 JNI 包装器中访问,您可以在跨越 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
之外的所有其他命令将继续照常工作。
为了提供更流畅的迁移体验,[email protected]
包仍然依赖于 @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
传递给 Native 中的非空参数时抛出错误
- 略微更改了生成的纯 C++ TurboModules 类和结构体的名称。我们从它们的名称中删除了
- 代码风格检查
- ESLint 配置在进行代码风格检查时不再运行 prettier
- C++
ScrollViewShadowNode
现在需要构造函数中的一个新bool includeTransform
参数- 从 RuntimeExecutor 中删除了
executeAsynchronously
和executeSynchronously_CAN_DEADLOCK
- 将
JsErrorHandlingFunc
重命名为OnJsError
(位于JsErrorHandler.h
中) - 将
handleJsError
重命名为OnJsError
(位于handleFatalError.h
中) - 从
ReactPrimitives.h
中删除了未使用的import
LongLivedObjectCollection
和LongLivedObject
的 get 方法现在接受一个 Runtime 参数- 将
utils/jsi.h
文件重命名为jsi-utils.h
- TextInput
- 移除已弃用的
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 间隙值。这会将某些方法(如
setGap
、setRowGap
和setColumnGap
)的参数从浮点数更改为动态类型 - Android 清单文件中需要
supportsRTL
- 支持百分比 flex 间隙值。这会将某些方法(如
- 运行时
- 从 ReactHostImpl 中移除
ReactJsExceptionHandler
- 当不使用默认模板时,使应用程序负责返回核心 TurboModules
- 从 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
- 将
- TextInput
- 移除已弃用的
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 为支持最低 SDK 版本 23 和最低 iOS 版本 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,React Native 0.75 将在 Expo SDK 51 中得到支持(有关如何在您的 Expo 项目中将 React Native 更新到 0.75.0 的说明,请参阅 此专用帖子)。
0.75 现在是 React Native 的最新稳定版本,0.72.x 已移至不受支持状态。有关更多信息,请参阅 React Native 的支持策略。我们计划在不久的将来发布 0.72 的最终生命周期结束更新。