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

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がある場合(本番環境での優雅な失敗には良いアイデアです)、レンダリングエラー後の次回の編集でレンダリングを再試行します。これにより、エラーboundaryがあると、常にrootアプリ状態にリセットされることを防ぐことができます。しかし、エラー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リフレッシュを失敗させる可能性があります たとえば、'./header''./Header'

Fast RefreshとHooks

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

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

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

時折、予期しない結果を招くことがあります。たとえ、空の依存関係の配列を持ったuseEffectであっても、Fast Refresh中に一度だけ再実行されます。

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