Cache Component
7m 35s
Cache Components の考え方
- Next.js はユーザーの待機時間を減らしたい
- ユーザーは主にデータ取得を待つことになる
- そこで、取得したデータをキャッシュし、再利用することですぐにデータを含んだ結果を表示させる
- あるいは、データ取得部分を遅れて表示させる(Suspense)ことでそれ以外の部分をすぐに表示させる
つまり、ユーザーを待たせる原因となるデータ取得を
- use cache でキャッシュして再利用
- Suspense で部分的に遅延表示
の二択で解決するのが Cache Components です。
キャッシュコンポーネントは現在オプションなので、 next.config.mjs で有効にする必要があります。
キャッシュコンポーネントを有効にすると、データ取得の実装をした際に Suspense or キャッシュ を強いるアラートが表示されるようになります。これによりユーザーは半強制的にいずれかのパフォーマンス改善を行うことになります。
キャッシュ
データが入った状態の画面が即座に表示されるのが理想なので、基本的にはキャッシュを使います。キャッシュはファイルやコンポーネント、関数に対し "use cache" を使います。
キャッシュはいつ更新されるのか
キャッシュは以下のタイミングで更新されます。
- キャッシュ生成から一定時間経過後にアクセスがあった場合
- デフォルトでは15分
- cacheLife で変更可能
- revalidatePath で該当のパスを指定したとき
- updateTag で該当のタグを指定したとき
- revalidateTag で該当のタグを指定したとき
属人的データは use cache: private を使う
まずビルド時点でデータ取得が行われ、その結果がキャッシュされ、その後のユーザーアクセス時にキャッシュが再利用されます。
しかし、ユーザーの情報に基づいて取得するデータ(属人的データ)はビルド時点で取得できないため、通常の "use cache" では対応できません。
たとえばマイページにユーザーが投稿した記事を表示する場合、マイページにアクセスしたユーザーのIDを受け取ってはじめて記事を取得できます。
そのようなデータに対しては "use cache: private" を使い、取得した結果をユーザーのブラウザにキャッシュします。
属人的データはユーザーIDを受け取ってはじめてデータ取得を開始できるため、絶対に待ち時間が発生します。そのため Suspense は必須になります。
上記のようにコンポーネントを分けて <Suspense> で囲むか、ページと同階層以上に loading.tsx を設置して画面全体を Suspense の対象とすることで初回の属人的データ表示を遅延させ、ビルドエラーも解決できます。
use cache: private は一定期間ブラウザにキャッシュされるので、同サイト内の別画面に遷移し、戻ってきた場合瞬時に同じデータが表示され、サーバーサイドへのリクエストは発生しません。
現在 use cache: private は機能していません。
事前予測ができないが属人的ではないデータは use cache: remote を使う
記事詳細ページのように、アクセスされてはじめて取得対象の記事IDが判明するケースでは、ビルド時に事前生成することができません。
そのようなデータに対しては "use cache: remote" を使い、取得した結果をサーバーサイドにキャッシュし、ユーザー間でシェアします。
use cache: private はユーザーの情報に基づいて取得するデータ(属人的データ)に有効ですが、ブラウザキャッシュなので他のユーザーとキャッシュをシェアできません。(セキュリティ的にもNG)
なお、記事の総量が少ない場合は generateStaticParams で事前生成することもできます。
これにより全記事の詳細画面がビルド時点で生成&キャッシュされます。ただし記事数が多い場合ビルド時に大量のデータリクエストが発生し、ビルド時間も長くなるためおすすめできません。
Suspense
Suspense を使うとデータ取得部分を遅延させ、それ以外の部分をすぐに表示できます。
ただし Suspense 単体で使う場合はキャッシュされないため、画面遷移のたびにデータ通信が発生します。基本的にはいずれかのキャッシュと組み合わせて使うことを推奨します。
レイアウトシフトに注意する
データ取得を待つ間、Suspense は fallback を表示します。一般的にフォールバックUIはローディングアイコンやスケルトンと呼ばれるグレーのボックスで表現します。
フォールバックUIの高さとデータ取得後の高さが異なる場合、データ取得後にがたつきが生じ、ユーザーに不快感を与えます(レイアウトシフト)。
そのため、フォールバックUIの高さとデータ取得後の高さが一致するようにします。結果の形が予測できる場合、sahdcn/ui の Skeleton がおすすめです。
取得後のコンテンツの高さが予測できない場合、フォールバックUIに十分な高さをとったり、Suspenseの粒度を広げて後続のUIも内包するなどの工夫が必要です。