Fast Refresh
Fast Refreshは、Next.jsに統合されたReactの機能で、ファイルを変更して保存する際に、一時的なクライアントサイドの状態を維持しながらブラウザページをライブリロードできます。これは、**9.4以降**のすべてのNext.jsアプリケーションでデフォルトで有効になっています。Fast Refreshが有効になっている場合、ほとんどの編集は1秒以内に反映されます。
仕組み
- **Reactコンポーネントのみをエクスポートする**ファイルを編集した場合、Fast Refreshはそのファイルのみのコードを更新し、コンポーネントを再レンダリングします。スタイル、レンダリングロジック、イベントハンドラー、エフェクトなど、そのファイル内のあらゆるものを編集できます。
- Reactコンポーネント*ではない*エクスポートを含むファイルを編集した場合、Fast Refreshはそのファイルと、それをインポートしている他のファイルの両方を再実行します。したがって、
Button.js
とModal.js
の両方がtheme.js
をインポートしている場合、theme.js
を編集すると両方のコンポーネントが更新されます。 - 最後に、**Reactツリー外のファイルにインポートされているファイル**を**編集**した場合、Fast Refreshは**フルリロードにフォールバックします**。Reactコンポーネントをレンダリングするファイルがありながら、**非Reactコンポーネント**にインポートされる値をエクスポートしている場合があります。たとえば、コンポーネントが定数をエクスポートし、非Reactユーティリティファイルがそれをインポートしている場合などです。そのような場合は、その定数を別のファイルに移行し、両方のファイルでインポートすることを検討してください。これにより、Fast Refreshが再び機能するようになります。その他のケースも通常は同様の方法で解決できます。
エラー耐性
構文エラー
開発中に構文エラーが発生した場合、それを修正してファイルを再度保存することができます。エラーは自動的に消え、アプリをリロードする必要はありません。**コンポーネントの状態が失われることはありません**。
ランタイムエラー
コンポーネント内でランタイムエラーを引き起こす間違いを犯した場合、コンテキストに応じたオーバーレイが表示されます。エラーを修正すると、アプリをリロードすることなく、オーバーレイは自動的に消えます。
エラーがレンダリング中に発生しなかった場合、コンポーネントの状態は保持されます。エラーがレンダリング中に発生した場合は、Reactは更新されたコードを使用してアプリケーションを再マウントします。
アプリにエラー境界がある場合(これは本番環境での優雅な失敗のために良いアイデアです)、レンダリングエラーの後の次の編集でレンダリングを再試行します。これは、エラー境界があることで、常にルートアプリの状態にリセットされるのを防ぐことができることを意味します。ただし、エラー境界はあまり細かすぎるべきではないことに注意してください。これらは本番環境でReactによって使用され、常に意図的に設計されるべきです。
制限事項
Fast Refreshは、編集中のコンポーネントのローカルReact状態を可能な限り保持しようとしますが、それは安全な場合に限られます。ファイルへの編集ごとにローカル状態がリセットされるいくつかの理由を以下に示します
- クラスコンポーネントのローカル状態は保持されません(関数コンポーネントとHooksのみが状態を保持します)。
- 編集しているファイルには、Reactコンポーネント以外に他のエクスポートがある可能性があります。
- 場合によっては、ファイルが
HOC(WrappedComponent)
のような高階コンポーネントを呼び出した結果をエクスポートすることがあります。返されたコンポーネントがクラスの場合、その状態はリセットされます。 export default () => ;
のような匿名のアロー関数は、Fast Refreshがローカルコンポーネントの状態を保持しない原因となります。大規模なコードベースでは、当社のname-default-component
codemodを使用できます。
コードベースの多くが関数コンポーネントとHooksに移行するにつれて、より多くのケースで状態が保持されることが期待できます。
ヒント
- Fast Refreshは、デフォルトで関数コンポーネント(およびHooks)のReactローカル状態を保持します。
- 場合によっては、状態を強制的にリセットし、コンポーネントを再マウントしたいことがあります。たとえば、マウント時のみに発生するアニメーションを調整している場合に便利です。これを行うには、編集しているファイルのどこかに
// @refresh reset
を追加します。このディレクティブはファイルローカルであり、Fast Refreshにそのファイル内で定義されたコンポーネントを編集ごとに再マウントするように指示します。 - 開発中に編集するコンポーネントに
console.log
やdebugger;
を配置できます。 - インポートは大文字と小文字を区別することに注意してください。インポートが実際のファイル名と一致しない場合、Fast Refreshとフルリロードの両方が失敗する可能性があります。たとえば、
'./header'
と'./Header'
などです。
Fast RefreshとHooks
可能な限り、Fast Refreshは編集間でコンポーネントの状態を保持しようとします。特に、useState
とuseRef
は、引数やHook呼び出しの順序を変更しない限り、以前の値を保持します。
useEffect
、useMemo
、useCallback
などの依存関係を持つHooksは、Fast Refresh中に*常に*更新されます。Fast Refreshが行われている間、それらの依存関係リストは無視されます。
たとえば、useMemo(() => x * 2, [x])
をuseMemo(() => x * 10, [x])
に編集した場合、x
(依存関係)が変更されていなくても再実行されます。Reactがそうしないと、あなたの編集が画面に反映されません!
場合によっては、これが予期せぬ結果につながることがあります。たとえば、依存関係が空の配列であるuseEffect
でも、Fast Refresh中に一度再実行されます。
しかし、useEffect
の occasional な再実行に耐性のあるコードを書くことは、Fast Refreshがなくても良い習慣です。これにより、後で新しい依存関係を導入しやすくなり、強く有効化を推奨するReact Strict Modeによって強制されます。
これは役に立ちましたか?