Fast Refresh
Fast Refresh は Next.js の機能で、Reactコンポーネントへの編集を即座に反映します。Fast Refresh は バージョン9.4以降 のすべての Next.js アプリケーションでデフォルトで有効になっています。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 () => <div />;
のような無名アロー関数は、Fast Refresh がローカルコンポーネント状態を保持しない原因になります。大規模なコードベースではname-default-component
codemod を使用できます。
コードベースの多くが関数コンポーネントとHooksに移行するにつれて、より多くのケースで状態が保持されるようになります。
ヒント
- Fast Refresh はデフォルトで関数コンポーネント(およびHooks)のReactローカル状態を保持します。
- 時々、状態を強制的にリセットし、コンポーネントを再マウントしたい場合があります。例えば、マウント時にのみ発生するアニメーションを調整する場合に便利です。これを行うには、編集しているファイルの任意の場所に
// @refresh reset
を追加します。このディレクティブはファイルローカルで、Fast Refresh にそのファイルで定義されたコンポーネントを毎回編集時に再マウントするよう指示します。 - 開発中に編集するコンポーネントに
console.log
やdebugger;
を入れることができます。 - インポートは大文字と小文字を区別することを覚えておいてください。インポートが実際のファイル名と一致しない場合、高速リフレッシュと完全リフレッシュの両方が失敗する可能性があります。例えば、
'./header'
と'./Header'
など。
Fast Refresh と Hooks
可能な場合、Fast Refresh は編集間でコンポーネントの状態を保持しようとします。特に、useState
と useRef
は、引数やHook呼び出しの順序を変更しない限り、以前の値を保持します。
依存関係を持つHook(useEffect
、useMemo
、useCallback
など)は、Fast Refresh中に常に更新されます。Fast Refreshが行われている間、依存関係のリストは無視されます。
例えば、useMemo(() => x * 2, [x])
を useMemo(() => x * 10, [x])
に編集すると、x
(依存関係)が変更されていなくても再実行されます。Reactがこれをしなければ、編集が画面に反映されないでしょう!
時々、これは予期しない結果を引き起こす可能性があります。例えば、空の依存関係配列を持つ useEffect
でさえ、Fast Refresh中に一度再実行されます。
しかし、useEffect
が時々再実行されることに耐えられるコードを書くことは、Fast Refreshがなくても良い習慣です。後で新しい依存関係を導入しやすくなり、React Strict Mode によって強制されます。これを有効にすることを強くお勧めします。