Next.jsにおけるfetchのタイミングと使い方
最近になってようやく Next.js における fetch の叩くべきタイミングや使い分けがわかるようになってきました。
今回は、現時点の自分なりの考えを書いていこうと思います。
前提
Next.js 環境下で fetch を叩く場合、call されるタイミングは大きく 3 つにわかれます。
- build 時(getStaticProps)
- render 前(getServerSideProps)
- render 後(useEffect, SWR, React Query など)
ただし getStaticProps については build 時に以外のタイミングでも call される可能性があります。
各々の関数について
getStaticProps
Static な、つまり静的な HTML に対し、サーバー側で api の call などを行い、props を通してデータを出力する目的で主に使用されます。
build 時に実行されるため、Cookie を扱うことができない点に注意が必要です。
build 時に実行され静的な HTML を出力するため、画面の描画はもっとも早いです。
また build 時以外に実行されるタイミングは、以下のとおりです。
- build 時には存在しなかったページが作成された
- revalidate に設定した時間を過ぎてページにアクセスがあった
- api 内で res.revalidate が実行された
個人的には getServerSideProps より getStaticProps を積極的に使うべきだと考えています。
getServerSideProps
ページにアクセスがあった際、render 前にサーバー側で api の call などを行い、props を通してデータを流し込む目的で主に使用されます。
render 前に実行されるため、Cookie を扱うことが可能です。
ただし render 前に実行されるため画面の描画は遅くなるデメリットが存在し、ユーザビリティが低下する恐れもあります。
useEffect, SWR, React Query
ページにアクセスがあった際、render が行われた後にクライアント側で api の call などを行い、state を通してデータを流し込む目的で主に使用されます。
個人的には api の向き先は同ドメインの /api 以下に向ける方針が無難だと思っています。
render 後に実行されるため Cookie を扱うことも可能ですが、api を call する場合は /api 以下で Cookie を扱うほうが無難かと思われます。
render 後に実行されるため画面の描画は早いですが、一瞬データが格納されていない状態が表示されます。
使い分け
api 周りで Cookie を扱う場合
getServerSideProps および useEffect, SWR, React Query のみ使用可能です。
api のレスポンスデータを SEO に反映する必要がある場合
getStaticProps および getServerSideProps のみ対応可能です。
最強の組み合わせ
ログインが不要なケースでは getStaticProps + SWR または React Query の組み合わせがオススメです。
ただし以下の点は考慮が必要です。
- 静的な HTML が出力されるため、サーバー側のファイル容量が増える
- 実装量が増え、求められる知識レベルも高いため、開発コストは高いです
ログインが必要なケースでは SWR または React Query のみで十分なケースが多いです。
ただしサーバー側に認証系を寄せる場合、middleware または getServerSideProps に実装が求められてくると思います。
getServerSideProps の使いみち
getServerSideProps を用いて実装を行うと、ログインの必要性にかかわらずあらゆるケースへ対応が可能となります。
ただし画面の描画があからさまに遅くなるため、使い所を見極めて使用する必要があります。
ファーストリリースは getServerSideProps で実装して、その後 getStaticProps などを使用して最適化を行うというのもアリかもしれません。
実装のコツ
getServerSideProps や getStaticProps 内で api の call を行う場合、どの程度実装をサーバー側に寄せるか悩んでしまいますが。
個人的には、たとえば axios を使用するのであれば response.data をそのまま props に流し込むのが無難かなーと思っています。
なぜなら、たとえば SWR を組み合わせた場合、response.data をそのまま state に格納するケースがほとんどだと思われますので、非常にシンプルかつ保守が容易な実装となります。
そんな感じです。