本文へスキップ

React Native 0.75 - レイアウトにおけるパーセンテージ値のサポート、新アーキテクチャの安定化、テンプレートとinitのアップデートなど

·14分間の読書
Gabriel Donadel Dall'Agnol
Gabriel Donadel Dall'Agnol
Expoのソフトウェアエンジニア
Siddharth Kulkarni
Siddharth Kulkarni
Coinbaseのソフトウェアエンジニア
Thibault Malbranche
Thibault Malbranche
Brigadのリードモバイルエンジニア
Blake Friedman
Blake Friedman
Metaのソフトウェアエンジニア
Riccardo Cipolleschi
Riccardo Cipolleschi
Metaのソフトウェアエンジニア
Nicola Corti
Nicola Corti
Metaのソフトウェアエンジニア

本日、React Native 0.75をリリースできることを嬉しく思います!

このリリースでは、`%`値をサポートするYoga 3.1、新アーキテクチャの安定化のためのいくつかの修正、React Nativeフレームワークを使用することを推奨する導入など、いくつかの機能を提供しています。

ハイライト

破壊的変更

ハイライト

Yoga 3.1とレイアウトの改善

React Native 0.74でYoga 3.0を最後にリリースして以来、アプリケーションの多くの改善と新しいレイアウト機能を継続的に追加してきました。React Native 0.75はYoga 3.1を搭載しており、公式Yogaのリリースブログ投稿で新機能の詳細を確認できます。

注目すべき、そして非常に要望の多かった機能の1つは、`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>
);
}

次のようにレンダリングされます。

AndroidiOS
Android GapsiOS Gaps

トランスレーションにおけるパーセンテージ値

`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>
);
}

次のようにレンダリングされます。

AndroidiOS
Android TranslationiOS Translation

新アーキテクチャの安定化

React Confで新アーキテクチャがベータ版であることを発表して以来、安定性を向上させるためのバグ修正と改善を数多く行ってきました。

新アーキテクチャを近い将来安定版と見なすことを目標としています。そのため、ここ数ヶ月は、旧アーキテクチャと新アーキテクチャのギャップを埋めることに重点を置いてきました。修正したバグと不足していた機能の例をいくつか挙げます。

  • Androidの`adjustsFontSizeToFit`の修正(#44075)
  • Androidでインラインビューで機能しない`textAlign`の修正(#44146)
  • iOSでテキストベースラインが上に移動する問題の修正(#44932)

Expoの皆さんと協力して、React Native Directoryに新アーキテクチャのサポートに関する情報を追加しました。これにより、ライブラリが既に新アーキテクチャをサポートしているかどうかをすぐに確認できます。

React Native Directory

新アーキテクチャに関するアンケートへのご参加もお待ちしております。このアンケートは、新アーキテクチャの展開における次のステップについて貴重なフィードバックを集めるために不可欠です。

また、新アーキテクチャでのUIManagerのサポートについて、新アーキテクチャワーキンググループで公開した投稿も共有したいと思います。この投稿では、Androidの`UIManager` APIの概要と、高度なアプリやライブラリの移行にどのように役立つのかを説明しています。

このリリースには、`jsi::Runtime`にアクセスするための推奨方法である新しいAPIも含まれています。

TurboModulesでの`jsi::Runtime`へのアクセス

これまで、ネイティブモジュールから`jsi::Runtime`にアクセスするための推奨方法は存在せず、利用者はフレームワークを回避して危険な方法でアクセスしていました。0.74では、`jsi::Runtime`への安全なアクセスを提供する実験的なAPIを導入し、0.75ではその安定性を発表できることを嬉しく思います。

jsi::Runtimeへのアクセス方法の例

iOSでは、Turbo Native Moduleをプロトコル`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 Native Moduleをインターフェース`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`はJNIラッパー`CallInvokerHolder`内の`ReactContext`を通じてアクセスできます。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`フォルダを提供しており、これはCommunity CLIによって新規プロジェクトの作成に使用されていました。これにより、テンプレートの更新が非常に遅くなりました。テンプレートの変更ごとに新しいReact Nativeリリースが必要だったためです。

フレームワークを使用するという最新の推奨事項に基づき、コアNPMパッケージ内に意見の強いテンプレートを提供することは、私たちのビジョンと一致しないと判断しました。

そのため、テンプレートを@react-native-community/templateパッケージに移動することにしました。

これにより、コミュニティは変更ごとにReact Nativeのリリースに依存することなく、テンプレートの保守と進化を容易に行うことができます。さらに、これはテンプレートをCommunity CLIにより近づけ、誰もがテンプレートを個別のパッケージとして検査および依存しやすくなります。

この変更は、Community CLIを使用して新規プロジェクトを作成するユーザーには完全に透過的であるはずです。今後、テンプレートに関する新しい問題は、テンプレートの問題トラッカーで報告する必要があります。アップグレードヘルパーなどのテンプレートに依存するさまざまなツールも同様に更新されており、通常どおり動作し続けます。

react-native initの廃止

テンプレートと同様に、`react-native init`コマンドも新しい推奨事項に合わせて調整されました。

従来、`react-native init`は新しいReact Nativeプロジェクトを作成するためのデフォルトのコマンドでした。しかし、2024年現在、このコマンドはフレームワークが提供するようなオンボーディングエクスペリエンスを提供しないと判断しています。そのため、これ以上推奨せず、代わりにExpoなどのフレームワークを使用する必要があります。

現在もCommunity CLIとテンプレートを使用して新しいプロジェクトを作成するために`react-native init`を使用できますが、次の警告が表示されます。

Init Deprecation

2024年12月31日以降、`init`コマンドはプロジェクトを作成しなくなります。次のいずれかを使用する必要があります。

  • Expoなどのフレームワークを、`npx create-expo-app`などの新しいプロジェクトを作成するための専用コマンドと共に使用します。
  • `npx @react-native-community/cli init`でCommunity 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におけるTouchableは、ジェネリック式では型として使用できなくなりました

`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はminSdk 23(Android 6.0)およびminIOSVersion 13.4をサポートする最後のReact Nativeバージョンであることを共有したいと思います。

React Native 0.76以降、minSdkバージョンは24(Android 7.0)、minIOSVersionは15.1になります。

詳細については、公式発表のAndroid向けiOS向けをご覧ください。

Android:JSIModuleが削除されました

`com.facebook.react.bridge.JSIModule`(ソース)は、ネイティブモジュールがAndroidで直接JSIにアクセスできるようにするために一時的に導入されたAPIでした。このAPIへのアクセサは0.74で非推奨となり、オープンソースでこのAPIが意味のある方法で使用されていないことを確認したため、0.75で削除します。Turbo Native Modulesを代替手段として使用できます。

Android:ポップアップメニューが別のパッケージに移動

0.74では、Androidの`PopUpMenu`を`@react-native`スコープの下の別のパッケージに移動しました。0.75では、コアに残っていたメソッドを削除しています。

  • UIManagerModule.showPopupMenu()
  • UIManagerModule.dismissPopupMenu()

代わりに、@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`を使用してください。

Community CLI:ram-bundleコマンドとprofile-hermesコマンドの削除

Community CLIから削除される2つの重要なコマンド、`ram-bundle`コマンドと`profile-hermes`コマンドについてお知らせします。

`ram-bundle`コマンドはReact Native 0.59で導入され、バンドルをメモリに直接ロードすることで実行できるようにしました。この機能は、デフォルトのJSエンジンであるHermesによって置き換えられました。`ram-bundle`コマンドは使用しないでください。

`profile-hermes`コマンドは、JavaScriptコードのCPUパフォーマンスをプロファイリングするためのツールでした。これは古い`.cpuprofile`形式を使用していましたが、最近のChromeバージョンではサポートされていません。スタンドアロンコマンドとしてこの機能を含めることも、デバッグツールの品質向上に取り組む中で廃止しつつあります。CPUプロファイリングは、実験的な新しいデバッガーの「プロファイラー」パネルからアクセスできるようになりました(注:ChromeからHermesに接続している場合はアクセスできません)。

その他の破壊的変更

一般

  • コード生成
    • 純粋なC++ TurboModulesで生成されるクラスと構造体の名前をわずかに変更しました。名前から`Cxx`トークンを削除しました。
    • 精度の誤差の可能性があるため、浮動小数点列挙型はサポートされなくなりました。
    • ネイティブの非nullable引数にJSから`null`を渡した場合、エラーをスローします。
  • リンティング
    • 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`に変更しました。
  • TextInput
    • 非推奨になった`onTextInput`コールバックを削除しました。
  • Pressability
    • `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`が必要になりました。
  • ランタイム
    • ReactHostImplから`ReactJsExceptionHandler`を削除しました。
    • デフォルトテンプレートを使用していない場合、コアターボモジュールを返す責任をアプリに負わせます。
  • DevSupport
    • `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 GerlemanJoe VilchesによるYoga 3.1とレイアウトの改善
  • Arushi Kesarwaniによる新しいアーキテクチャでのUIManagerのサポート
  • Phillip PanによるTurboModulesでのjsi::Runtimeへのアクセス
  • Alan LeeSoe LynnによるminSdk 23とminIOSVersion 13.4をサポートする最後のバージョン
  • Kudo Chienによる自動リンクのパフォーマンス向上
  • Alex Huntによる`ram-bundle`コマンドと`profile-hermes`コマンドの削除

0.75へのアップグレード

既存のプロジェクトでは、アップグレードに関するドキュメントに加えて、React Native Upgrade Helperを使用して、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の最終的なライフエンドアップデートを公開する予定です。