メインコンテンツまでスキップ

Fast Refresh

Fast Refreshは、Next.jsに統合されたReactの機能で、ファイルに変更を保存するときに一時的なクライアントサイドの状態を維持しながらブラウザページをライブリロードすることができます。これは9.4以降のすべてのNext.jsアプリケーションでデフォルトで有効になっています。Fast Refreshが有効な場合、ほとんどの編集は1秒以内に反映されるはずです。

仕組み

  • Reactコンポーネントのみをエクスポートするファイルを編集した場合、Fast Refreshはそのファイルのコードのみを更新し、コンポーネントを再レンダリングします。そのファイル内のスタイル、レンダリングロジック、イベントハンドラ、エフェクトなど、何でも編集できます
  • Reactコンポーネントではないエクスポートを持つファイルを編集した場合、Fast Refreshはそのファイルとそれをインポートしている他のファイルを再実行します。たとえば、Button.jsModal.jsの両方がtheme.jsをインポートしている場合、theme.jsを編集すると両方のコンポーネントが更新されます
  • 最後に、React treeの外部のファイルによってインポートされているファイルを編集した場合、Fast Refreshはフルリロードにフォールバックします。Reactコンポーネントをレンダリングするファイルがあり、同時に非Reactコンポーネントによってインポートされる値をエクスポートすることがあります。たとえば、コンポーネントが定数をエクスポートし、非Reactユーティリティファイルがそれをインポートする場合です。この場合、定数を別のファイルに移動し、両方のファイルにインポートすることを検討してください。これにより、Fast Refreshが再び機能するようになります。他のケースも通常は同様の方法で解決できます

エラー耐性

構文エラー

開発中に構文エラーを起こした場合、修正してファイルを再度保存できます。エラーは自動的に消えるので、アプリをリロードする必要はありません。コンポーネントの状態は失われません

ランタイムエラー

コンポーネント内でランタイムエラーを引き起こすミスをした場合、コンテキストオーバーレイが表示されます。エラーを修正すると、オーバーレイは自動的に消え、アプリはリロードされません。

エラーがレンダリング中に発生しなかった場合、コンポーネントの状態は保持されます。エラーがレンダリング中に発生した場合、Reactは更新されたコードを使用してアプリケーションを再マウントします。

アプリにerror boundariesがある場合(これは本番環境での優雅な失敗のために推奨されます)、レンダリングエラーの次の編集時にレンダリングを再試行します。これにより、error boundaryを持つことで常にrootアプリ状態にリセットされるのを防ぐことができます。ただし、error boundaryはあまりにも細かくしないように注意してください。これらは本番環境で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.logdebugger;を入れることができます
  • インポートは大文字と小文字を区別することを忘れないでください。インポートが実際のファイル名と一致しない場合、fastおよびfull refreshが失敗することがあります。たとえば、'./header''./Header'です

Fast RefreshとHooks

可能な場合、Fast Refreshは編集間でコンポーネントの状態を保持しようとします。特に、useStateuseRefは、引数やHook呼び出しの順序を変更しない限り、以前の値を保持します。

依存関係を持つHooks(useEffectuseMemouseCallbackなど)は、Fast Refresh中に常に更新されます。Fast Refreshが行われている間、依存関係のリストは無視されます。

たとえば、useMemo(() => x * 2, [x])useMemo(() => x * 10, [x])に編集すると、x(依存関係)が変更されていなくても再実行されます。Reactがそうしなければ、編集が画面に反映されません!

時には、これが予期しない結果をもたらすことがあります。たとえば、依存関係の配列が空のuseEffectでさえ、Fast Refresh中に一度再実行されます。

しかし、useEffectの再実行に耐性のあるコードを書くことは、Fast Refreshがなくても良いプラクティスです。これにより、後で新しい依存関係を追加しやすくなり、React Strict Modeによって強制されます。これを有効にすることを強くお勧めします。