Fast Refresh
Fast RefreshはReact Nativeの機能で、Reactコンポーネントの変更に対するフィードバックをほぼ瞬時に得ることができます。Fast Refreshはデフォルトで有効になっており、React Native開発者メニューの「Enable Fast Refresh」で切り替えることができます。Fast Refreshを有効にすると、ほとんどの編集は1〜2秒以内に反映されます。
仕組み
- Reactコンポーネントのみをエクスポートするモジュールを編集した場合、Fast Refreshはそのモジュールのコードだけを更新し、コンポーネントを再レンダリングします。そのファイル内では、スタイル、レンダリングロジック、イベントハンドラ、エフェクトなど、あらゆるものを編集できます。
- Reactコンポーネントではないエクスポートを持つモジュールを編集した場合、Fast Refreshはそのモジュールと、それをインポートしている他のモジュールの両方を再実行します。つまり、
Button.js
とModal.js
の両方がTheme.js
をインポートしている場合、Theme.js
を編集すると両方のコンポーネントが更新されます。 - 最後に、Reactツリー外のモジュールからインポートされているファイルを編集した場合、Fast Refreshはフォールバックしてフルリロードを実行します。Reactコンポーネントをレンダリングしつつ、非Reactコンポーネントによってインポートされる値もエクスポートしているファイルがあるかもしれません。例えば、コンポーネントが定数もエクスポートしており、それをReact以外のユーティリティモジュールがインポートしている場合です。その場合は、その定数を別のファイルに移動し、両方のファイルからインポートすることを検討してください。これにより、Fast Refreshが再び機能するようになります。他のケースも通常は同様の方法で解決できます。
エラー耐性
Fast Refreshセッション中に構文エラーを犯した場合、それを修正してファイルを再度保存すれば、レッドボックスは消えます。構文エラーのあるモジュールは実行が妨げられるため、アプリをリロードする必要はありません。
モジュールの初期化中にランタイムエラーを犯した場合(例えば、StyleSheet.create
の代わりにStyle.create
と入力するなど)、エラーを修正すればFast Refreshセッションは継続されます。レッドボックスは消え、モジュールは更新されます。
コンポーネント内でランタイムエラーにつながる間違いを犯した場合も、エラーを修正すればFast Refreshセッションは継続されます。その場合、Reactは更新されたコードを使ってアプリケーションを再マウントします。
アプリにエラー境界 (error boundaries) がある場合(本番環境でのグレースフルな失敗のために良いアイデアです)、レッドボックスが表示された後、次の編集でレンダリングを再試行します。その意味で、エラー境界を持つことで、常にルートアプリ画面に飛ばされるのを防ぐことができます。ただし、エラー境界はあまりにも細かすぎるべきではないことに注意してください。これらは本番環境でReactによって使用されるものであり、常に意図的に設計されるべきです。
制限事項
Fast Refreshは、編集中のコンポーネントのローカルなReactのstateを保持しようとしますが、それが安全な場合に限られます。ファイルを編集するたびにローカルなstateがリセットされる場合、いくつかの理由が考えられます。
- クラスコンポーネントではローカルなstateは保持されません(関数コンポーネントとフックのみがstateを保持します)。
- 編集中のモジュールが、Reactコンポーネントに加えて他のエクスポートを持っている可能性があります。
- 高階コンポーネント(例:
createNavigationContainer(MyScreen)
)を呼び出した結果をモジュールがエクスポートすることがあります。返されたコンポーネントがクラスである場合、stateはリセットされます。
長期的には、コードベースの多くが関数コンポーネントとフックに移行するにつれて、より多くのケースでstateが保持されることが期待できます。
ヒント
- Fast Refreshは、デフォルトで関数コンポーネント(およびフック)内のReactのローカルなstateを保持します。
- 場合によっては、stateを強制的にリセットし、コンポーネントを再マウントしたいことがあります。例えば、マウント時にのみ発生するアニメーションを調整している場合に便利です。これを行うには、編集中のファイルのどこかに
// @refresh reset
を追加します。このディレクティブはそのファイルにローカルであり、Fast Refreshに対して、そのファイルで定義されたコンポーネントを編集のたびに再マウントするよう指示します。
Fast Refreshとフック
可能な場合、Fast Refreshは編集間でコンポーネントのstateを保持しようとします。特に、useState
とuseRef
は、引数やフックの呼び出し順序を変更しない限り、以前の値を保持します。
useEffect
、useMemo
、useCallback
などの依存関係を持つフックは、Fast Refresh中は常に更新されます。Fast Refreshが行われている間、依存関係のリストは無視されます。
例えば、useMemo(() => x * 2, [x])
をuseMemo(() => x * 10, [x])
に編集すると、x
(依存関係)が変更されていなくても再実行されます。もしReactがそうしなければ、あなたの編集は画面に反映されないでしょう!
これにより、予期しない結果が生じることがあります。例えば、依存関係の配列が空のuseEffect
でさえ、Fast Refresh中に一度再実行されます。しかし、useEffect
が時々再実行されることに耐えられるコードを書くことは、Fast Refreshがなくても良い習慣です。これにより、後で新しい依存関係を導入しやすくなります。