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

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;を入れることができます
  • インポートは大文字小文字を区別することを忘れないでください。インポートが実際のファイル名と一致しない場合、高速リフレッシュと完全リフレッシュの両方が失敗することがあります。たとえば、'./header''./Header'です。

Fast RefreshとHooks

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

依存関係があるHooks、例えばuseEffectuseMemo、およびuseCallbackは、Fast Refresh中に常に更新されます。Fast Refreshが行われている間、その依存関係リストは無視されます。

たとえば、useMemo(() => x * 2, [x])useMemo(() => x * 10, [x])に編集すると、依存関係であるxが変更されていないにもかかわらず、再実行されます。Reactがこれをしなければ、あなたの編集は画面に反映されないでしょう!

このため、時々予期しない結果が生じることがあります。たとえば、依存関係の配列が空のuseEffectであっても、Fast Refresh中に1回再実行されます。

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