🚀

【Next.js和訳】Basic Features/Fast Refresh

2021/10/02に公開約3,400字

この記事について

この記事は、Basic Features/Fast Refreshの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Fast Refresh

Fast Refresh は Next.js の機能で、React コンポーネントに加えられた編集を瞬時にフィードバックすることができます。Fast Refresh は、9.4 以降のすべての Next.js アプリケーションでデフォルトで有効になっています。Next.js の Fast Refresh を有効にすると、コンポーネントの state を失うことなく、ほとんどの編集内容が 1 秒以内に表示されます。

仕組み

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

エラー修復力

シンタックスエラー

開発中にシンタックスエラーが発生した場合、エラーを修正して再度ファイルを保存することができます。エラーは自動的に消えますので、アプリを再読み込みする必要はありません。また、コンポーネントの state が失われることもありません

ランタイムエラー

コンポーネント内でランタイムエラーにつながるミスをした場合、コンテクストオーバーレイが表示されます。エラーを修正すると、アプリをリロードすることなく、オーバーレイが自動的に解除されます。

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

アプリにエラーバウンダリがある場合(本番での潔い失敗のためには良いアイデアです)、レンダリングエラーの後の次の編集でレンダリングを再試行します。つまり、エラーバウンダリを持つことで、常にルートアプリの state にリセットされることを防ぐことができます。ただし、エラーバウンダリはあまり細かくすべきではないことに留意してください。これらは React が本番で使用しているものであり、常に意図的に設計すべきものです。

制限事項

Fast Refresh は、編集しているコンポーネントのローカルな React の state を保持しようとしますが、それが安全な場合に限られます。ファイルを編集するたびにローカルの state がリセットされることがあるのは、以下の理由によります。

  • クラスコンポーネントでは、ローカルの state は保存されません(state が保存されるのは、関数コンポーネントと Hooks のみです)。
  • 編集中のファイルは、React コンポーネントに加えて他のエクスポートがあるかもしれません。
  • 時々、ファイルは、HOC(WrappedComponent)のような高次のコンポーネントを呼び出した結果をエクスポートするでしょう。返されたコンポーネントがクラスの場合、ステートはリセットされます。
  • export default () => <div />;のような匿名の矢印関数は、Fast Refresh がローカルコンポーネントの state を保持しない原因となります。大規模なコードベースでは、name-default-component codemodを使用することができます。

コードベースの多くが関数コンポーネントや Hooks に移行すると、より多くのケースで state が保存されるようになります。

ヒント

  • Fast Refresh は、デフォルトで関数コンポーネント(および Hooks)の React ローカルの state を保持します。
  • 時には、強制的に state をリセットして、コンポーネントを再マウントしたいことがあります。例えば、マウント時にのみ発生するアニメーションを調整する場合などに便利です。これを行うには、編集中のファイルのどこかに// @refresh resetを追加します。このディレクティブは、ファイルにローカルなもので、編集のたびに、そのファイルで定義されたコンポーネントを再マウントするように、ファーストリフレッシュに指示します。
  • 開発中に編集するコンポーネントにconsole.logまたはdebugger;を入れることができます。

Fast Refresh と Hooks

可能な限り、高速リフレッシュでは、編集の間にコンポーネントの state を維持しようとします。特に、useStateuseRefは、その引数や Hook calls の順序を変更しない限り、以前の値を維持します。

useEffectuseMemouseCallbackなどの依存関係のある Hooks は、高速更新時に常に更新されます。依存関係のリストは、高速更新が行われている間は無視されます。

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

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

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

Discussion

ログインするとコメントできます