跳至主要內容

React Native 0.74 - Yoga 3.0、橋接器 Free 新架構及更多功能

·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、預設在全新架構下採用的橋接器 Free 模式、批次處理的 onLayout 更新 (全新架構),以及 Yarn 3 作為新專案的預設套件管理器。

我們也移除了已棄用的 API,包括移除 PropTypesPushNotificationIOS 的重大變更。在 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 先前在處理 marginpaddingborder 時,反轉了在 row-reverse 容器上設定的 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'

全新架構:預設橋接器 Free 模式

在此版本中,我們將橋接器 Free 模式設為啟用全新架構時的預設模式。您可以在這篇文章中深入瞭解我們切換至預設橋接器 Free 模式的相關資訊。為了讓轉換更順暢,我們強化了互通層以涵蓋橋接器 Free 模式,並與數個程式庫合作,以確保它們從一開始就能在橋接器 Free 模式中運作。

橋接器 Free 模式不是我們唯一著重的互通層:我們也改善了全新轉譯器互通層。最令人興奮的是,它現在預設為啟用:您不需要指定必須通過它的組件!您可以在這裡閱讀更多相關資訊。

最後,如果您想深入瞭解全新架構,可以在 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 (請參閱 commit)。

如果您的應用程式或程式庫依賴 PropTypes,我們強烈建議您遷移至類型系統 (例如 TypeScript)。

PushNotificationIOS 的 API 變更 (已棄用)

在 React Native 0.74 中,我們正採取步驟來移除已棄用的 PushNotificationIOS 程式庫。此版本中的變更重點在於移除對舊版 iOS API 的參照。PushNotificationIOS 已遷移至 Apple 的 User Notifications 框架,並公開新的 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 時,soundName 將為 null。

移除 Flipper React Native 外掛程式

現在不支援使用 Flipper 檢查 React Native 版面配置、網路要求和 其他 React Native 外掛程式功能。在 0.74 中,我們已從新的 React Native 專案中移除了原生 Flipper 程式庫和設定程式碼。這表示更少的依賴性和更快的本機設定速度 (請參閱 原始 RFC)。

您可以在 Upgrade Helper 中查看在您的應用程式中移除 Flipper 的差異。如果您想在現有應用程式中保留 Flipper,請忽略相關的差異行。

💡 重新整合 Flipper

Flipper 仍可用作獨立工具來除錯 Android 或 iOS 應用程式,並且可以透過遵循 Flipper 文件手動整合 (Android 指南iOS 指南)。

我們建議團隊投入切換至 Android Studio 和 Xcode 中的原生除錯工具。

提示

取代 Flipper

有許多專用的除錯工具可取代 Flipper 功能。如需更多資訊,我們建議閱讀 Jamon Holmgren 撰寫的優秀文章為什麼您的 React Native 應用程式不需要 Flipper,以及如何在沒有它的情況下生存

JavaScript 除錯

使用 Hermes Debugger 仍是我們針對 0.74 建議的除錯選項。您也可以試用 實驗性新除錯器,這也是 Expo 中的預設除錯器。這仍然是早期預覽版 — 已知問題和更新可以在這裡追蹤。

其他重大變更

一般

  • 讓樣式中的 start/end 始終參照書寫方向 (#42251)。

Android

  • FabricUIManagerProvider 中移除 JSIModule* (#42059)。
    • 此 API 在開放原始碼中未使用 — 請改用 TurboModules
  • 棄用 UIManagerModule.showPopupMenuUIManagerModule.dismissPopupMenu (#42441)

iOS

  • 從 iOS codegen 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 Upgrade Helper 來檢視現有專案中 React Native 版本之間的程式碼變更。

若要建立新專案

npx react-native@latest init MyProject

如果您使用 Expo,Expo SDK 51 將支援 React Native 0.74。

資訊

0.74 現在是 React Native 的最新穩定版本,而 0.71.x 已移至不受支援。如需更多資訊,請參閱 React Native 的支援政策。我們的目標是在 5 月初發布 0.71 的最終終止生命週期更新。