Fast Refresh
Fast Refreshは、ファイルを保存する際に一時的なクライアントサイドの状態を維持しながら、ブラウザページをライブリロードできるNext.jsに統合されたReact機能です。これは9.4以降のすべてのNext.jsアプリケーションでデフォルトで有効になっています。Fast Refreshが有効な場合、ほとんどの編集は1秒以内に反映されます。
動作の仕組み
- Reactコンポーネントのみをエクスポートするファイルを編集した場合、Fast Refreshはそのファイルのコードのみを更新し、コンポーネントを再レンダリングします。そのファイル内のスタイル、レンダリングロジック、イベントハンドラー、エフェクトなど、anything を編集できます。
- 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'
vs'./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中に1回再実行されます。
しかし、useEffect
の偶発的な再実行に耐性のあるコードを書くことは、Fast Refreshがなくても良い習慣です。後で新しい依存関係を導入しやすくなり、React Strict Modeによって強制されます。これを有効にすることを強くお勧めします。