UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【技術本まとめ】実践Next.jsを読んでのメモ

takepepeさんの新しい本『実践Next.js』を読んだのでメモ

AppRouterは使ったことがなかったので、この本で情報のキャッチアップをしたい

本の内容は4章まではAppRouterの基礎情報で、それ以降はかなり実践的なサンプルアプリの実装の話

自分としては以前からNext.jsのPagesRouterは使っていたので、あの機能はAppRouterではどうなるのかという差分を中心に読んでいった

全体的にかなり分かりやすくまとまっていたので、とても読みやすかった

以下はメモ

  • ハイドレーション:任意のDOMにイベントハンドラーをアタッチすること
  • Client Componentからimportされるコンポーネントや関連ファイルもブラウザ向けにバンドルされる
  • 全部に"use client"をつける必要はない→親がClient Componentなら不要
    • usePathnameを使うならClient Componentにする
    • 汎用性の高いコンポーネントは親がServerかClientのどちらにもなりうるので、"use client"は最小限に留める
  • fetch関数のデフォルトのキャッシュ設定
    • 更新頻度が低い:静的データ(何も設定しなければこれとして扱われる)
    • 更新頻度が高い:動的データ(fetch(url, { cache: 'no-store' }) を指定すると毎回取得する)
  • devモードでサーバー立ち上げるとキャッシュの挙動が把握できないので、ビルドして起動する
    →その前にキャッシュの破棄(.next/cache/fetch-cacheを消す)をすること
  • Routeのレンダリング
  • 動的レンダリングRouteになる要因は3つ
    • ① 動的データ取得が行われると動的レンダリングになる
      • { cache: 'no-store' } 有れば動的
      • ビルド時にレンダリングを試みるので、動的レンダリングの場合はビルド時にAPIと接続できないとビルドエラーになる
    • ② 動的関数の使用
      • Cookie参照、リクエストヘッダー参照、URL検索パラメータ参照など
    • ③ Dynamic Segmentの使用
      • パスの一部が [categoryName] になっている場合はcategoryNameがparamsとして取り出せるので、この機能を使った場合
  • import { notFound } form "next/navigation" 知らなかった
  • route.tsを使うとWeb APIになる
  • global-error.tsはハンドリングされなかった例外が最後に行き着く場所("use client"が必要)
  • Route Groups:グルーピングのためにフォルダを作りたいが、パスの一部としたくないフォルダはフォルダ名を () で囲む

    • この下にlayout.tsxをとかおくと、それぞれのLayoutが適用される
    • 全くリーティング対象にしたくない場合は _ をフォルダ名の接頭辞につける(例:_components)
  • 3.3 Parallel RoutesとIntercepting Routesは新しい考え方

    • @を接頭辞につけたフォルダはURLのパスとして無視される
    • 「slot」と呼ばれるノードがchildrenのようにpropsで渡される
    • @配下のSubtreeと表示しているRoute Segmentが一致したらそのノードがレンダリングされる
    • default.tsxは一致するまでの間のslotとして表示される(返すものがなければnullを返す)
    • Intercepting RoutesはRouteを「横取り」するRoute定義でParallelと合わせると、@配下のSubtreeと表示しているRoute Segmentが一致したらそのRoutesを横取りする
    • (.)とか (..) とか相対パスのように定義する
  • 3.4 静的なメタデータはmetadataオブジェクトをexportすれば良い、動的の場合は generateMetadata 関数をexportする

    • メタデータと画面表示時の2回リクエスト送ってしまうので「Requestのメモ化」を内部で行なっている(6.3節で解説)
    • メタデータは継承されるため、個々の設定は不要
      →ただし、パラメータが異なるとメモ化されない
       →パラメータの差異が出ないように目的別に関数を作り共通化すると良い
    • generateMetadata関数の第二引数のResolvingMetadataで継承された親のメタデータを参照できる。
  • 4.1 page.tsxとroute.tsは同じフォルダに入れるとコンフリクトを起こす

  • 4.2 画面と同様にビルド時に以下の要因が検出されると動的Route Handleとみなされる

    1. Dynamic Segment値の参照 (※第二引数にDynamicSegmentのparamsがある)
    2. Requestオブジェクトの参照(※第一引数にRequestオブジェクトがある)
    3. 動的関数の使用(cookies関数とか)
    4. GETとHEAD以外のHTTP関数のexport(POSTとか)
    5. Segment Config Optionsの指定( export const dynamic = "force-dynamic";)
  • 4.3 Route Handlerの良いところはNext.js自身が認証認可機能を備えたWebサーバーなので、画面側からのリクエストにユーザー情報を含めなくてもCookieを頼りにログインユーザーを参照できる
  • 6.4 Next.jsは「Incremental Cache」というデータ取得結果をキャッシュし、必要に応じて更新する組み込みキャッシュシステムが存在する。
    →デフォルトでオン。一年間有効。
  • fetch("url", { next: { revalidate: 60 * 60 }}) で有効期間変更
    このように有効期間を指定するRevalidateを Time-based Revalidation という
  • 6.6 cache関数を使うとfetch関数以外での「Requestのメモ化」ができる
    • Reactコンポーネント内では使わないこと
    • データ取得関数の引数はプリミティブ値でなければならない
import { cache } from "react";
...
export const getProfileFromScreenName = cache(() => {});
  • 6.7 fetch関数以外のデータキャッシュをしたい場合は、 unstable_cache を使う
    • fetchData: キャッシュされるデータを取得するための非同期関数
    • keyPars: キャッシュを一意に識別するためのキーとして使われる文字列の配列
    • options: キャッシュの動作を制御するオブジェクト
    • Reactコンポー内で利用可能
import { unstable_cache }. from "next/cache";
...
const data = unstable_cache(fetchData, keyParts, options)();

ここまでが8章で、9章以降は別の機会に書く