- スムーズな再生とインタラクションの維持:UIコントロールとメディアは、負荷の大きい更新中も応答し続けます。
- バックグラウンド処理の最適化:データの読み込みや計算によってインターフェイスがフリーズしません。
- ナビゲーションの向上:複雑なレンダリングタスクの実行中でも、画面間の切り替えをスムーズに行えます。
フック、コンポーネント、ヘルパー関数
useTransitionとuseDeferredValueという2つのReactフックを使用すると、更新を管理したり、アプリのパフォーマンスを制御したりできます。不要な再レンダリングを防ぐため、これらのフックは、必ずコンポーネントのメモ化と組み合わせて使用してください。
Reactには、負荷の大きいコンポーネントのレンダリング中にフォールバックコンポーネントを表示するためのSuspenseコンポーネントも用意されています。lazyヘルパー関数を使用すると、負荷の大きいコンポーネントの読み込みを遅らせ、その後の更新に備えてキャッシュしておくことができます。
useTransition
useTransitionフックでは、状態更新を優先させて即座に処理するか、トランジション(優先度が低く、中断可能)として処理するかを指定できます。これにより、フィルタリング操作によってUIの更新が遅れるという、検索インターフェイスの一般的な課題が解決されます。デバウンスなどの手法を使用する代わりに、検索入力の応答性を維持しつつ、フィルタリングの優先度を低く設定できるようになりました。
このフックは、次の2つの値を返します。
isPending:優先度の低い更新が保留中かどうかを表すブール値。読み込み状態を示す場合に役立ちますstartTransition:緊急性が低い状態更新をラップする関数
setQueryによって即座に更新されますが、フィルタリング操作はstartTransitionによって延期されます。トランジション中に読み込みインジケーターが表示され、準備ができた時点で結果が表示されます。
startTransitionは関数の実行を遅延させず、setResultsの更新を低優先度としてマークするだけです。Reactは、setQuery(高優先度のキュー)を最初に処理し、その後でsetResults(低優先度のキュー)を処理します。
このフックを直接使用できない場合は、startTransition関数を直接使用してください。
使用するタイミング: コンポーネントの状態変数を制御できる場合(検索インターフェイス、ナビゲーション、大規模なリストの更新)。
使用を避けるべきタイミング: コンポーネントの状態を直接制御できない場合(代わりにuseDeferredValueを使用します)
useDeferredValue
useDeferredValueフックを使用すると、重要な更新が完了するまで、プロパティや外部ソースの値の更新を遅らせることができます。たとえば、コンポーネントが検索結果を受け取ったとき、検索結果のプレビューを更新するという負荷の大きい処理を延期する一方で、見出しの検索語は即座に更新できます。 使用するタイミング: 状態変数にアクセスできない場合に、負荷の大きい計算や非同期操作をトリガーするプロパティ 使用を避けるべきタイミング: 状態変数を制御するコンポーネント(代わりにuseTransitionを使用します)
Suspenseとlazy
Suspenseコンポーネントは、(使用可能になった時点で)コードまたはデータの読み込み中にフォールバックコンテンツを表示します。lazy関数は、オンデマンドでコンポーネントをインポートします(必要に応じてコードを取得)。これらは単独で使用することも、一緒に使用することもできます。Suspenseを単独で使用してデータを取得
この例では、MediaListがジャンルデータを取得してレンダリングしている間、Suspenseは読み込みプレースホルダー(MediaSkeleton)を表示します。
lazyとSuspenseを併用し、既定の読み込み状態でコードを分割
この例では、LazyLoadedScreenのレンダリング時にMassiveComponentをインポートすると同時に、SuspenseがMediaSkeletonプレースホルダーを表示します。
並列レンダリングの実装
並列レンダリングを実装するには、次の手順に従います。手順1:コンポーネントレベルのメモ化を追加
メモ化により、不要な再レンダリングと計算を防ぐことができます。コンポーネントの子では、useTransition()またはuseDeferredValue()を使用することが重要です。メモ化を行わないと、親が更新した時点で子が再レンダリングされるため、並列レンダリングのメリットが失われます。
メモ化しない場合:
この例のSearchComponentは、useTransitionをレンダリングする際、メモ化がどのように影響するかを示しています。メモ化しないと、結果に変更がない場合でも、キーストロークのたびにSearchResultsが再レンダリングされます。
memoを使用すると、検索が変更されたときのみSearchResultsが再レンダリングされます。
手順2:優先度ベースの更新を適用
入力、クリック、スクロールなどの操作はすぐにユーザーにフィードバックする必要がありますが、データ処理やUIの更新は遅らせることができます。更新に優先順位を付けるには、useTransitionとuseDeferredValueを使用します。
更新に優先順位を付けない場合:
setQuery)のたびに負荷の大きい操作(performSearch)が即座に実行され、両方の更新が完了するまでUIがブロックされます。キーストロークのたびに検索操作の完了を待つ必要があるため、ユーザーは入力時に遅延を感じます。
更新に優先順位を付ける場合:
performSearch)がトランジションで実行されるようになったため、入力更新(setQuery)を即座に完了できます。検索結果がバックグラウンドで更新されている間、ユーザーはスムーズに入力できます。更新が保留されているときは読み込みインジケーターが表示されます。
テストと検証
並列レンダリングの実装をテストするには、以下のツールを使用します。React Native DevToolsプロファイラー
メモ化と優先順位の高い更新の実装をテストするには、React Native DevToolsプロファイラーを使用します。- ChromeでReact Native DevToolsを開きます。
- [Profiler] タブを選択します。
- 記録ボタンをクリックします。
- テストインタラクションを実行します(検索語句の入力、リストのスクロールなど)。
- 記録を停止します。
- フレームグラフに不要な再レンダリングやトランジションマーカーがないことを確認します。

