🐷
React.cache を知らないと損する
結論
RSC で React.cache
を知らないと損する
前提
なぜ?
React.cache
を使う場合と使わない場合で比較したら一目瞭然
1. cache を使わない場合
React.cache
を使わない場合のサンプルコードを以下に記す。
// app/page.tsx
export default async function HelloAgain1() {
const currentUser = await loadCurrentUser();
return (
<div>
HelloAgain1 {currentUser.name}
<HelloAgain2 />
</div>
);
}
async function HelloAgain2() {
const currentUser = await loadCurrentUser();
return <div>HelloAgain2 {currentUser.name}</div>;
}
const loadCurrentUser = async () => {
console.log("loadCurrentUser");
await new Promise((resolve) => setTimeout(resolve, 1000));
return { id: "1", name: "Kimura" };
};
ページが読み込まれるまでの時間を
DevTools の NetWorkタブ で確認する。結果は??
2.06秒!
同じページ内で2回 loadCurrentUser
が呼ばれているから当然!
2. cache を使う場合
React.cache
を使う場合のサンプルコードを以下に記す。
// app/page.tsx
import { cache } from "react";
export default async function HelloAgain1() {
const currentUser = await loadCurrentUser();
return (
<div>
HelloAgain1 {currentUser.name}
<HelloAgain2 />
</div>
);
}
async function HelloAgain2() {
const currentUser = await loadCurrentUser();
return <div>HelloAgain2 {currentUser.name}</div>;
}
const loadCurrentUser = cache(async () => {
console.log("loadCurrentUser");
await new Promise((resolve) => setTimeout(resolve, 1000));
return { id: "1", name: "Kimura" };
});
ページが読み込まれるまでの時間を
DevTools の NetWorkタブ で確認する。結果は??
1.08秒!
同じページ内で2回 loadCurrentUser
がコード上では呼ばれているが、同じリクエストだから2回目のリクエストはキャッシュされていることが分かる
補足情報
Next.js の Request Memoization の
セクションに以下の様に英語で記載されている
Good to know:
- Request memoization is a React feature, not a Next.js feature. It's included here to show how it interacts with the other caching mechanisms.
- Memoization only applies to the GET method in fetch requests.
- Memoization only applies to the React Component tree, this means:
- It applies to fetch requests in generateMetadata, generateStaticParams, Layouts, Pages, and other Server Components.
- It doesn't apply to fetch requests in Route Handlers as they are not a part of the React component tree.
- For cases where fetch is not suitable (e.g. some database clients, CMS clients, or GraphQL clients), you can use the React cache function to memoize functions.
⬇︎⬇︎⬇︎日本語に翻訳する⬇︎⬇︎⬇︎
知っておくとよいこと:
- リクエストのメモ化はReactの機能であり、Next.jsの機能ではありません。
- メモ化はフェッチリクエストのGETメソッドにのみ適用されます。
- メモ化はReactコンポーネントツリーにのみ適用されます。つまり
- generateMetadata、generateStaticParams、Layouts、Pages、その他のServer Componentsのフェッチリクエストに適用されます。
- ルートハンドラはReactコンポーネントツリーの一部ではないため、フェッチリクエストには適用されません。
- フェッチが適切でない場合(一部のデータベースクライアント、CMSクライアント、GraphQLクライアントなど)には、React.cache 関数を使用して関数をメモ化できます。
最後にもう一度結論
Request Memoization が
使用できる状況では React.cache
を使おう!
特に GraphQL を使用しているプロジェクトや
fetch を使用していないプロジェクトでは必ず使おう!
Discussion