ファストリフレッシュ
ファストリフレッシュは、Next.jsに統合されたReactの機能で、ファイルに変更を保存したときに、一時的なクライアントサイドの状態を維持しながら、ブラウザページをライブリロードできます。 9.4以降のすべてのNext.jsアプリケーションでデフォルトで有効になっています。ファストリフレッシュが有効になっている場合、ほとんどの編集は1秒以内に表示されます。
仕組み
- **Reactコンポーネントのみをエクスポートするファイル**を編集した場合、ファストリフレッシュはそのファイルのコードのみを更新し、コンポーネントを再レンダリングします。スタイル、レンダリングロジック、イベントハンドラ、エフェクトなど、そのファイル内の anything を編集できます。
- Reactコンポーネント*ではない*エクスポートを含むファイルを編集した場合、ファストリフレッシュはそのファイルとそれをインポートする他のファイルの両方を再実行します。そのため、 `Button.js` と `Modal.js` の両方が `theme.js` をインポートする場合、 `theme.js` を編集すると両方のコンポーネントが更新されます。
- 最後に、**Reactツリー外のファイルによってインポートされているファイルを編集する**と、ファストリフレッシュは**フルリロードにフォールバックします**。Reactコンポーネントをレンダリングするが、**React以外のコンポーネント**によってインポートされる値もエクスポートするファイルがある場合があります。たとえば、コンポーネントが定数をエクスポートし、React以外のユーティリティファイルがそれをインポートする場合があります。この場合は、定数を別のファイルに移行し、両方のファイルにインポートすることを検討してください。これにより、ファストリフレッシュが再び機能するようになります。他のケースも同様の方法で解決できることがよくあります。
エラー耐性
構文エラー
開発中に構文エラーが発生した場合、エラーを修正してファイルを再度保存できます。エラーは自動的に消えるため、アプリをリロードする必要はありません。 **コンポーネントの状態は失われません**。
ランタイムエラー
コンポーネント内で実行時エラーが発生するようなミスをした場合、コンテキストオーバーレイが表示されます。エラーを修正すると、アプリをリロードすることなく、オーバーレイは自動的に閉じます。
レンダリング中にエラーが発生しなかった場合は、コンポーネントの状態は保持されます。レンダリング中にエラーが発生した場合は、Reactは更新されたコードを使用してアプリケーションを再マウントします。
アプリにエラーバウンダリがある場合(本番環境での正常な障害処理のために推奨されます)、レンダリングエラーが発生した後の次の編集でレンダリングが再試行されます。つまり、エラーバウンダリを設定することで、常にルートアプリの状態にリセットされるのを防ぐことができます。ただし、エラーバウンダリは過度に細かく設定すべきではありません。エラーバウンダリは本番環境でReactによって使用されるため、常に意図的に設計する必要があります。
制限事項
ファーストリフレッシュは、編集中のコンポーネントのローカルReactの状態を保持しようとしますが、安全な場合にのみ行います。ファイルの編集ごとにローカル状態がリセットされる場合がある理由をいくつか示します。
- クラスコンポーネントではローカル状態は保持されません(関数コンポーネントとHooksのみが状態を保持します)。
- 編集中のファイルには、Reactコンポーネントに加えて他のエクスポートが含まれている場合があります。
- 場合によっては、ファイルが
HOC(WrappedComponent)
のような高階コンポーネントを呼び出した結果をエクスポートすることがあります。返されたコンポーネントがクラスの場合、その状態はリセットされます。 export default () => <div />;
のような匿名アロー関数は、ファーストリフレッシュがローカルコンポーネントの状態を保持しない原因となります。大規模なコードベースの場合は、name-default-component
コードモッドを使用できます。
コードベースのより多くの部分が関数コンポーネントとHooksに移行するにつれて、より多くの場合で状態が保持されることが期待できます。
ヒント
- ファーストリフレッシュは、デフォルトで関数コンポーネント(およびHooks)のReactローカル状態を保持します。
- 状態を強制的にリセットし、コンポーネントを再マウントしたい場合があります。たとえば、マウント時にのみ発生するアニメーションを調整する場合に便利です。これを行うには、編集中のファイルの任意の場所に
// @refresh reset
を追加します。このディレクティブはファイルに対してローカルであり、ファーストリフレッシュに、編集ごとにそのファイルで定義されたコンポーネントを再マウントするように指示します。 - 開発中に編集するコンポーネントに
console.log
またはdebugger;
を配置できます。 - インポートは大文字と小文字を区別することに注意してください。インポートが実際のファイル名と一致しない場合、高速リフレッシュと完全リフレッシュの両方が失敗する可能性があります。たとえば、
'./header'
と'./Header'
です。
ファーストリフレッシュとHooks
可能な場合、ファーストリフレッシュは編集間でコンポーネントの状態を保持しようとします。特に、`useState`と`useRef`は、引数またはHook呼び出しの順序を変更しない限り、以前の値を保持します。
`useEffect`、`useMemo`、`useCallback`などの依存関係を持つHooksは、ファーストリフレッシュ中に常に更新されます。ファーストリフレッシュ中は、依存関係のリストは無視されます。
たとえば、`useMemo(() => x * 2, [x])`を`useMemo(() => x * 10, [x])`に編集すると、依存関係である`x`が変更されていない場合でも再実行されます。Reactがこれを行わなかった場合、編集内容は画面に反映されません。
場合によっては、予期しない結果が生じる可能性があります。たとえば、依存関係の配列が空の`useEffect`でも、ファーストリフレッシュ中に1回再実行されます。
ただし、`useEffect`の偶発的な再実行に対して耐性のあるコードを作成することは、ファーストリフレッシュがない場合でも良い習慣です。これにより、後で新しい依存関係を簡単に導入できるようになり、強く推奨されるReact Strict Modeによって強制されます。
これは役に立ちましたか?