Slide 1

Slide 1 text

Next.js の fetch 拡張と キャッシュ機構の違いを理解する まっつー / @ryo-manba 2024/06/25 Vercel Meetup #1 1

Slide 2

Slide 2 text

自己紹介 まっつー サイボウズのフロントエンドエンジニア NextUI の team member X: @ryo_manba GitHub: @ryo-manba 2

Slide 3

Slide 3 text

This Talk ・React と Next.js の fetch 拡張から Fetch Deduping と Data Cache の違いを 理解する ・React.cache や Next.js の unstable_cache の使 い方を知る 3

Slide 4

Slide 4 text

React Removes `fetch` React 19 RC でネイティブの fetch Web API に 対する patch が削除された https://github.com/facebook/react/pull/28896 4

Slide 5

Slide 5 text

Next.js implementation React `fetch` Next.js 15 RC では React の fetch 拡張を実装した 5 https://github.com/vercel/next.js/pull/65058

Slide 6

Slide 6 text

React の fetch 拡張がしていたこと コンポーネントツリー内の同一リクエストを重複排除(Request Deduping) して1つにまとめる 6

Slide 7

Slide 7 text

fetch の拡張による Request Deduping ・同じURLとオプションを持つリクエストをメモ化する ・GET/HEAD のみに適用される ・レンダリング中のみ有効のため、キャッシュの鮮度を管理 したり、再検証は不要 7

Slide 8

Slide 8 text

fetch の拡張による Request Deduping async function hello() { // 実際に送信されるリクエストは1つだけ const res1 = await fetch("http://localhost/hello"); const res2 = await fetch("http://localhost/hello"); return {res1, res2}; } 8

Slide 9

Slide 9 text

fetch の拡張による Request Deduping 9 async function Hello() { // 実際送信されるリクエストは1つだけ const res1 = await fetch("http://localhost/hello"); const res2 = await fetch("http://localhost/hello"); return {res1, res2} } ・DB に直接アクセスしたい ・GraphQL や POST only な社内向け の API を利用している

Slide 10

Slide 10 text

fetch の拡張による Request Deduping 10 async function Hello() { // 実際送信されるリクエストは1つだけ const res1 = await fetch("http://localhost/hello"); const res2 = await fetch("http://localhost/hello"); return {res1, res2} } ・DB に直接アクセスしたい ・GraphQL や POST only な社内向け の API を利用している React.cache を使う

Slide 11

Slide 11 text

React.cache の概要 ・関数の戻り値をキャッシュし、同じ入力で再度呼び出され た際にキャッシュされた結果を返す ・リクエストごとにメモ化された関数のキャッシュは無効化 されるため、キャッシュの鮮度の管理は不要 11

Slide 12

Slide 12 text

React.cache による Request Deduping const getUser = cache(async (id) => { return await db.user.query(id); }) async function Hello() { // DB へのリクエストは1回のみ const res1 = await getUser(1); const res2 = await getUser(1); }
 12

Slide 13

Slide 13 text

React.cache による Request Deduping 13

Slide 14

Slide 14 text

セキュリティの対応 ・React.cache の実装に AsyncLocalStorage が使用されて いるため、外部から干渉を防ぎ、安全に状態管理が行える ・fetch の拡張の実装には React.cache を使用し、url と option を文字列化した値をキーとしてレスポンスを保存し ている 14 https://zenn.dev/cybozu_frontend/articles/react-cache-an

Slide 15

Slide 15 text

15 Next.js の fetch 拡張 と Data Cache

Slide 16

Slide 16 text

Next.js の fetch 拡張による Data Cache ・組み込みの Data Cache を使用し、リクエストやデプロイ メントにまたがって結果を永続化する ・fetch のオプションでキャッシュの有効期間や再検証に使 用する Tag の設定ができる 16 // キャッシュを有効化する fetch(url, {cache: ‘force-cache’}) // 1分後に再検証する fetch(url, { next: { revalidate: 60 }})

Slide 17

Slide 17 text

Next.js の fetch 拡張による Data Cache fetch のレスポンスを Data Cache に保存する 17

Slide 18

Slide 18 text

unstable_cache による Data Cache ・Data Cache を使用し、リクエストとデプロイメントにわ たって結果を保存する(fetch の拡張と同様) ・有効期間や再検証に使用する Tag を設定する const getCachedUser = unstable_cache( async (id) => getUser(id), // データ取得する非同期関数 ["my-app-user"], // データ識別用のキー { tags: ["my-app-user"] } // キャッシュの制御用のタグ ); 18

Slide 19

Slide 19 text

Next.js の fetch 拡張の今後 ・Next.js でもコミュニティのフィードバックに基づいて fetch の拡張を削除することを検討されている ・`revalidateAfter(60)` のような API が導入される可能性が ある 19 https://youtu.be/VBlSe8tvg4U?si=uRuv-CQuliZYuNXX

Slide 20

Slide 20 text

まとめ ・React の fetch 拡張(現在は Next.js の実装) ・Request の重複排除(Request Deduping)を実現 ・対応する機能は React.cache ・Next.js の fetch 拡張 ・Data Cache を利用してデータアクセスの効率化 ・対応する機能は unstable_cache 20