跳至主要内容

React Native 0.74 - Yoga 3.0、无桥新架构等更新

·阅读时长 12 分钟
Hur Ali
Hur Ali
Callstack 软件工程师
Alan Hughes
Alan Hughes
Expo 软件工程师
Alfonso Curbelo
Alfonso Curbelo
Coinbase 软件工程师
Alex Hunt
Alex Hunt
Meta 软件工程师
Nicola Corti
Nicola Corti
Meta 软件工程师

今天,我们发布了 React Native 0.74!此版本添加了 Yoga 3.0、在新架构下默认使用无桥模式、批量化的 onLayout 更新(新架构)以及将 Yarn 3 作为新项目的默认包管理器。

我们还删除了已弃用的 API,包括删除 PropTypes 以及对 PushNotificationIOS 的重大更改。在 Android 上,SDK 23(Android 6.0)现在是最小支持版本。

亮点

重大更改

亮点

Yoga 3.0

新的布局行为

React Native 0.74 包含了 Yoga 3.0,这是我们布局引擎的最新版本。Yoga 3.0 通过使样式更可预测来改进布局,并支持渲染为 Web 编写的组件。

React Native 继续有意保留一些不正确的布局行为,因为发现修复它们会影响大量实际组件。在未来的 React Native 版本中,将能够更细粒度地配置布局一致性。

警告

React Native 以前翻转 在处理 row-reverse 容器上设置的 marginpaddingborder 时的 left/right(以及 start/end)边缘。现在,这些属性的行为与 Web 保持一致。以前依赖于边缘反转的代码可能需要更新才能继续正确渲染。

样式之前之后
<View
style={{
flexDirection: 'row',
backgroundColor: 'red',
margin: 10,
width: 200,
height: 100,
}}>
<View
style={{
flexDirection: 'row-reverse',
backgroundColor: 'blue',
flex: 1,
marginLeft: 50,
}}>
<View
style={{
backgroundColor: 'green',
height: '50%',
flex: 1,
marginLeft: 50,
}}
/>
</View>
</View>

Previous layout

New layout

支持 align-content: 'space-evenly'

Yoga 3.0 带来了对 alignContent: 'space-evenly' 的支持。space-evenly 使用均匀间隔的间隙在多行弹性容器中分布行,并放置在行和容器边缘之间。

Visual reference for alignContent behaviors
来源:万维网联盟

支持 position: 'static'

信息

position: 'static' 仅在新架构中受支持。

标记为 position: 'static' 的元素可能不会偏移,并且在确定绝对定位元素的 包含块 时不会被考虑在内。这允许相对于其不是直接父级的祖先来定位元素。

<View
style={{
backgroundColor: 'blue',
width: 200,
height: 200,
flexDirection: 'row-reverse',
}}>
<View
style={{
backgroundColor: 'red',
width: 100,
height: 100,
position: 'static',
}}>
<View
style={{
backgroundColor: 'green',
width: 25,
height: '25%',
left: 25,
top: 25,
position: 'absolute',
}}
/>
</View>
</View>

Static Example

请注意,绿色的 <View> 声明了 lefttop,并且它相对于蓝色的 <View> 定位,而不是它的父级。

当未设置 position 时,React Native 继续默认为 position: 'relative'

新架构:默认使用无桥模式

在此版本中,当启用新架构时,我们将无桥模式设置为默认模式。您可以在 此帖子 中了解更多关于我们切换到无桥模式作为默认模式的信息。为了使过渡更加平滑,我们增强了互操作层以涵盖无桥模式,并与多个库合作,以确保它们从第一天起就能在无桥模式下工作。

无桥模式不是我们唯一改进的互操作层:我们也改进了新渲染器互操作层。最令人兴奋的是,它现在默认启用:您无需指定必须通过它的组件!您可以 在此处 阅读更多相关信息。

最后,如果您想了解有关新架构的更多信息,可以在 react-native-new-architecture 存储库中找到文档。当新架构成为默认架构时,这些信息将合并到 reactnative.dev 中。

新架构:批量化的 onLayout 更新

onLayout 回调中的状态更新现在已批量处理。以前,onLayout 事件中的每个状态更新都会导致新的渲染提交。

function MyComponent(props) {
const [state1, setState1] = useState(false);
const [state2, setState2] = useState(false);

return (
<View>
<View
onLayout={() => {
setState1(true);
}}>
<View
onLayout={() => {
// When this event is executed, state1's new value is no longer observable here.
setState2(true);
}}>
</View>
</View>
);
}

在 0.74 中,setState1setState2 更新被一起批量处理。此更改是 React 中的预期行为,并且可以减少重新渲染次数。

危险

此更改**可能会破坏**依赖于未批处理状态更新的代码。您需要重构此代码以使用更新函数或等效项。

新项目的 Yarn 3

Yarn 3 现在是使用 React Native Community CLI 初始化的新项目的默认 JavaScript 包管理器。

Yarn 3.x 将与nodeLinker: node-modules一起使用,这是一种提供与 React Native 库兼容性的模式。它取代了 Yarn Classic (1.x,已弃用) 作为之前的默认值。要升级现有应用中的 Yarn 版本,您可以按照此指南进行操作。

$ yarn --help
━━━ Yarn Package Manager - 3.6.4 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

$ yarn <command>

Community CLI 还支持通过--pm标志使用其他包管理器初始化项目(了解更多)。

重大更改

Android 最低 SDK 提升 (Android 6.0)

React Native 0.74 对 Android SDK 版本有最低要求 23(Android 6.0)。之前,此要求为 Android 5.0(API 21)。请参阅我们对此更改的上下文此处

额外福利:Android 应用大小减少

最低 SDK 的提升以及我们在原生构建中的一些改进,使我们能够大幅减少用户设备上的应用大小。

例如,使用 React Native 0.74 创建的新应用在用户设备上占用空间减少了约 13%,从而节省了约 4MB 的设备空间。

Side-by-side comparison of a new React Native app in the Android system storage view

移除已弃用的PropTypes

在 0.74 之前,React Native 继续附带PropTypes,这是一个自 2017 年 React 15.5 以来一直被弃用的 API!我们现在从 React Native 中删除所有内置的PropTypes,从而减小应用大小(最小化包中减少 26.4kB)并减少内存开销。

已删除以下PropTypes属性:Image.propTypesText.propTypesTextInput.propTypesColorPropTypeEdgeInsetsPropTypePointPropTypeViewPropTypes(请参阅提交)。

如果您的应用或库依赖于PropTypes,我们强烈建议迁移到 TypeScript 等类型系统。

PushNotificationIOS 的 API 更改(已弃用)

在 React Native 0.74 中,我们正在采取措施删除已弃用的PushNotificationIOS库。此版本中的更改侧重于删除对旧版 iOS API 的引用。PushNotificationIOS 已迁移到 Apple 的用户通知框架,并公开了用于计划和处理通知的新 API。

在下一个版本(0.75)中,我们计划**删除此库**,将其从 React Native 核心转移到社区包@react-native-community/push-notification-ios中。如果您仍然依赖于 PushNotificationIOS,则需要在下一个版本发布之前迁移。

API 更改

RCTPushNotificationManager上的didRegisterUserNotificationSettings:回调是一个空操作,已被删除。

RCTPushNotificationManager上的以下回调已弃用,将在 0.75 中删除

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

为了使用getInitialNotification()检索启动应用的通知,您现在需要在RCTPushNotificationManager上显式设置initialNotification

[RCTPushNotificationManager setInitialNotification:response.notification];

在 JS 端,Notification上的属性已更改。alertActionrepeatInterval现已弃用,将在 0.75 中删除

type Notification = {
...
// NEW: Seconds from now to display the notification.
fireIntervalSeconds?: ?number,

// CHANGED: Used only for scheduling notifications. Will be null when
// retrieving notifications using `getScheduledLocalNotifications` or
// `getDeliveredNotifications`.
soundName?: ?string,

// DEPRECATED: This was used for iOS's legacy UILocalNotification.
alertAction?: ?string,

// DEPRECATED: Use `fireDate` or `fireIntervalSeconds` instead.
repeatInterval?: ?string,
};

最后,PushNotificationIOS.removeEventListener上的handler参数未使用,已被删除。

💡 如何迁移

iOS

您的AppDelegate需要实现UNUserNotificationCenterDelegate。这应该在应用启动时在application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:中完成(有关更多详细信息,请参阅Apple 文档)。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;

return YES;
}

实现userNotificationCenter:willPresentNotification:withCompletionHandler:,当通知到达且应用处于前台时,会调用此方法。使用completionHandler确定是否会向用户显示通知,并相应地通知RCTPushNotificationManager

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
// This will trigger 'notification' and 'localNotification' events on PushNotificationIOS
[RCTPushNotificationManager didReceiveNotification:notification];
// Decide if and how the notification will be shown to the user
completionHandler(UNNotificationPresentationOptionNone);
}

要处理点击通知,请实现userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:。请注意,如果您在userNotificationCenter:willPresentNotification:withCompletionHandler:中设置了显示前台通知,则应仅在其中一个回调中通知RCTPushNotificationManager

如果点击的通知导致应用启动,请调用setInitialNotification:。如果之前未由userNotificationCenter:willPresentNotification:withCompletionHandler:处理通知,则也调用didReceiveNotification:

- (void)  userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
// This condition passes if the notification was tapped to launch the app
if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
// Allow the notification to be retrieved on the JS side using getInitialNotification()
[RCTPushNotificationManager setInitialNotification:response.notification];
}
// This will trigger 'notification' and 'localNotification' events on PushNotificationIOS
[RCTPushNotificationManager didReceiveNotification:response.notification];
completionHandler();
}

最后,删除以下方法并将逻辑调整到上面将调用的回调中

  1. application:didReceiveLocalNotification: [已弃用]
  2. application:didReceiveRemoteNotification: [已弃用]
  3. application:didReceiveRemoteNotification:fetchCompletionHandler: [未弃用,但已被UNUserNotificationCenterDelegate方法取代]

删除任何application:didRegisterUserNotificationSettings:RCTPushNotificationManager的对应didRegisterUserNotificationSettings:的使用。

示例:请参阅 RNTester 的AppDelegate.mm

JS

  1. 删除对alertAction的任何引用。
  2. 删除对removeEventListener的任何调用的handler参数。
  3. repeatInterval的任何用法替换为使用fireDatefireIntervalSeconds触发多个通知。
  4. 请注意,当从getScheduledLocalNotifications()getDeliveredNotifications()返回的Notification上访问soundName时,它将为 null。

删除 Flipper React Native 插件

现在不再支持使用Flipper检查 React Native 布局、网络请求以及其他 React Native 插件功能。在 0.74 中,我们已从新的 React Native 项目中删除了原生 Flipper 库和设置代码。这意味着依赖项更少,本地设置更快(请参阅原始 RFC)。

您可以在升级助手中查看在您的应用中删除 Flipper 的差异。如果您想在现有应用中保留 Flipper,请忽略相关的差异行。

💡 重新集成 Flipper

Flipper 仍然可以作为独立工具用于调试 Android 或 iOS 应用,并且可以通过遵循 Flipper 文档(Android 指南iOS 指南)手动集成。

我们建议团队投资切换到 Android Studio 和 Xcode 中的原生调试工具。

提示

替换 Flipper

有一些专门的调试工具可以替换 Flipper 的功能。有关更多信息,我们建议您阅读 Jamon Holmgren 撰写的精彩文章为什么您的 React Native 应用不需要 Flipper 以及如何在没有它的情况下继续使用

JavaScript 调试

使用Hermes 调试器仍然是我们推荐的 0.74 调试选项。您还可以尝试实验性新调试器,它也是 Expo 中的默认调试器。这仍然是一个早期预览版 - 可以在此处跟踪已知问题和更新。

其他重大更改

通用

  • 使样式中的start/end始终引用书写方向(#42251)。

Android

  • 移除 FabricUIManagerProvider 中的 JSIModule* (#42059).
    • 此 API 在开源版本中未使用 - 请改用 TurboModules
  • 弃用 UIManagerModule.showPopupMenuUIManagerModule.dismissPopupMenu (#42441)

iOS

  • 从 iOS 代码生成 CLI 中删除 configFilenameconfigKey 参数 (#41533).
  • 更改 bundleURL 的处理方式 (#43994).
    • 之前,bundleURL 在 React Native 启动时设置在一个实例变量中,并且无法更新它。
    • 现在,bundleUrl 是一个函数,在需要时重新评估,从而可以在刷新时使用不同的 URL。
    • 此更改仅在您在应用启动后更改 bundleURL 变量时才会影响您的应用。在这种情况下,请将更新变量的逻辑移动到 AppDelegate 中的 bundleURL 函数 中。

请参阅 完整更改日志 以获取所有重大更改的完整列表。

已知问题

iOS

  • 使用多个窗口时的边缘情况:当主窗口处于非活动状态并且系统尝试显示对话框时,对话框不会在屏幕上的正确位置显示。修复程序将在 #44167 中提供,并将在 0.74.1 中发布。

致谢

React Native 0.74 包含来自 57 位贡献者的 1673 多次提交。感谢大家的辛勤工作!

感谢所有在发布后帮助编写功能文档的其他作者

升级到 0.74

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

创建新项目

npx react-native@latest init MyProject

如果您使用 Expo,React Native 0.74 将在 Expo SDK 51 中得到支持。

信息

0.74 现在是 React Native 的最新稳定版本,并且 0.71.x 将不再受支持。有关更多信息,请参阅 React Native 的支持策略。我们计划在 5 月初发布 0.71 的最终生命周期结束更新。