💭

React Navigationの画面遷移の高速化 【React Native】

2023/10/24に公開

この記事の内容

React NavigationのStackナビゲーションをキビキビした動きにしたい。

  • 遷移先の画面のレンダリングを高速にすることが鉄則。
  • ただし、以下の施策でユーザー体験を向上することができる:
    • React Navigationのトランジション・アニメーションを高速なものに変更する。
    • React Navigationの画面遷移が終わってからレンダリングを開始することで、体感スピードをあげることができる。

デモ映像

https://www.youtube.com/shorts/BAHrLJ-z6Tg

サンプルコード

https://github.com/mshk/faster-react-navigation-transition-sample

この記事の読者

React Nativeでアプリを作ってみたけど、なんとなく動きがゆったりしていると感じている開発者。

React Navigationの画面遷移の仕組み

React Navigationは、デフォルトでは以下のような動作になっています。

遷移先のスクリーンのレンダリングが遅いと画面遷移が開始されないため、画面をタップしてからの「待ち」が長くなり体験が悪くなります。根本的には遷移先の画面のレンダリングを高速に完了することが解決策になりますが、ネットワーク経由でデータを取得する画面など遅延が避けがたいケースがあります。

遷移先の画面のレンダリングを待たずにトランジションさせる

遷移先の画面のレンダリング速度が遅い場合、ひとまず「ロード中」などのシンプルなレンダリングを行うことで、React Navigationのトランジションをスタートさせます。

export const TargetScreen = () => {
const [isReady, setIsReady] = useState(false);

  useDidMount(() => {
    setTimeout(() => setIsReady(true), 0);
  }
  return !isReady 
    ? <Text>ロード中</Text>
    : <>{//レンダリングに時間がかかるコンポーネント}</>
}

これによって、画面をタップしてからトランジションが開始されるまでの時間が短く、常に一定になります。最終的にレンダリングが終了するまでの時間は変わらないのですが、アニメーションの開始が遅かったり時間がまちまちだとユーザー体験としては良くないので「体感上」の改善効果があります。

(追記) InteractionManagerを使うやり方

React Navigation公式ドキュメントに記載の方法をフィードバックして頂いたので追記します。
https://reactnavigation.org/docs/use-focus-effect/#delaying-effect-until-transition-finishes

InteractionManagerを使うことでReact Navigationのトランジション(アニメーション)が完了したタイミングをキャッチします。

以下のメリットがあるとのことです。

  • 画面遷移完了後に処理が行われることを保証できる
  • 処理中に別の画面遷移しようとしたときもパフォーマンスが落ちにくい

トランジションの時間を短くする

React Navigationのトランジションは、何も設定しなければ default のアニメーションがレンダリングされます。iOS/Androidそれぞれに異なるアニメーションが設定されていますが、いずれもトランジションにかかる時間は固定されていて、変更ができません(300ms程度かかっている模様)。

iOS

iOSには simple_push というアニメーションが用意されていて、遷移先の画面が右から左にスクロールする default に良く似た動きになっています。こちらのアニメーションは、defaultと違って duration を変更することが可能です。
今回は「80ms」を設定してみます。

<Stack.Screen
  name="DemoScreen"
  component={DemoScreen}
  options={{
    animation: 'simple_push',
    animationDuration: 80,
  }}
/>

Android

Andoidは、標準ではdurationを変更できるトランジションがないため、別記事で扱います。
以下のコードでiOSと同じ右から左にスライドするトランジションで、durationを変更できました。

<Stack.Screen
  name="DemoScreen"
  component={DemoScreen}
  options={{
    animation: 'simple_push',
    animationDuration: 80,
    ...TransitionPresets.SlideFromRightIOS,
    transitionSpec: {
      open: { config: { duration: 80 } },
      close: { config: { duration: 80 } },
    },
  }}
/>

修正後の動作

まとめ

  • トランジションのアニメーションを変更してアニメーションの時間を短縮することで、画面遷移の時間減らすことができた。
  • 画面遷移時のトランジション・アニメーションを先にトリガーすることで、ユーザーが画面をタップしてからのフィードバックを最適化して体感上の速度を改善できた。

Discussion