本文へ移動

React Native 0.74 - Yoga 3.0、ブリッジレスNew Architecture、その他多数

·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、New Architectureの下でデフォルトのブリッジレスモード、バッチ処理されたonLayoutアップデート(New Architecture)、および新規プロジェクトのデフォルトパッケージマネージャーとしてのYarn 3を追加しました。

また、PropTypesの削除やPushNotificationIOSに対する破壊的変更など、非推奨APIの削除も行っています。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コンテナに設定されたmarginpadding、またはborderを処理する際に、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
出典: World Wide Web Consortium

position: 'static'のサポート

情報

position: 'static'は、New Architectureでのみサポートされています。

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>を基準に配置されていることに注意してください。

React Nativeは、positionが設定されていない場合、デフォルトでposition: 'relative'になります。

New Architecture: デフォルトでブリッジレス

このリリースでは、New Architectureが有効になっている場合、ブリッジレスモードをデフォルトにしています。デフォルトとしてブリッジレスへの切り替えの詳細については、この投稿を参照してください。移行をスムーズにするために、ブリッジレスをカバーする相互運用レイヤーを強化し、いくつかのライブラリと連携して、初日からブリッジレスで動作するようにしました。

ブリッジレスは私たちが取り組んだ唯一の相互運用レイヤーではありません。New Renderer相互運用レイヤーも改善しました。最もエキサイティングな点は、それがデフォルトで有効になっていることです。通過する必要があるコンポーネントを指定する必要はありません!それらについてはこちらで詳しく読むことができます。

最後に、New Architectureの詳細については、react-native-new-architectureリポジトリでドキュメントを見つけることができます。New Architectureがデフォルトになると、この情報はreactnative.devに組み込まれます。

New Architecture: バッチ処理された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は、React Nativeライブラリとの互換性を提供するモードであるnodeLinker: node-modulesと共に使用されます。これにより、以前のデフォルトであった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は2017年のReact 15.5以降非推奨となっているAPIであるPropTypesを同梱していました!現在、React Nativeからすべての組み込みPropTypesを削除し、アプリサイズ(縮小版バンドルで26.4kB)とメモリオーバーヘッドを削減しています。

次のPropTypesプロパティが削除されました:Image.propTypesText.propTypesTextInput.propTypesColorPropTypeEdgeInsetsPropTypePointPropTypeViewPropTypesコミットを参照)。

アプリまたはライブラリが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の変更

RCTPushNotificationManagerdidRegisterUserNotificationSettings:コールバックはノーオペレーションであり、削除されました。

RCTPushNotificationManagerの次のコールバックは非推奨となり、0.75で削除されます。

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

getInitialNotification()を使用してアプリを起動した通知を取得するには、RCTPushNotificationManagerinitialNotificationを明示的に設定する必要があります。

[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.removeEventListenerhandlerパラメーターは使用されておらず、削除されました。

💡移行方法

iOS

AppDelegateUNUserNotificationCenterDelegateを実装する必要があります。これは、アプリの起動時に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:でフォアグラウンド通知を表示するように設定した場合、これらのコールバックのいずれか1つで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の使用を、代わりにfireDateまたはfireIntervalSecondsを使用して複数の通知を発生させることで置き換えます。
  4. getScheduledLocalNotifications()getDeliveredNotifications()から返されたNotificationsoundNameにアクセスする場合、soundNameはnullになります。

Flipper React Nativeプラグインの削除

React Nativeレイアウト、ネットワークリクエスト、およびその他のReact Nativeプラグイン機能の検査にFlipperを使用することは、現在サポートされていません。0.74では、新しいReact NativeプロジェクトからネイティブのFlipperライブラリと設定コードを削除しました。これは、依存関係の減少とより迅速なローカル設定を意味します(元のRFCを参照)。

アプリからFlipperを削除するdiffは、Upgrade Helperで見ることができます。既存のアプリでFlipperを保持する場合は、関連するdiff行を無視してください。

💡Flipperを再統合するには

Flipperは、AndroidまたはiOSアプリのデバッグのためのスタンドアロンツールとして引き続き使用でき、Flipperのドキュメントに従って手動で統合できます(AndroidガイドiOSガイド)。

Android StudioとXcodeのネイティブデバッグツールへの切り替えに投資することをお勧めします。

ヒント

Flipperの代替

Flipperの機能に取って代わる、多くの専用のデバッグツールがあります。詳細については、Jamon Holmgrenによる優れた記事「React NativeアプリでFlipperが必要ない理由とその方法」をお読みください。

JavaScriptデバッグ

0.74では、Hermesデバッガーの使用が推奨されるデバッグオプションです。実験的な新しいデバッガーも試すことができます。これは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バージョン間のコード変更を確認するには、React Native Upgrade Helperアップグレードドキュメントをご利用ください。

新規プロジェクトの作成

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の最終的なEOLアップデートを公開する予定です。