0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React.cache を知らないと損する

Posted at

結論

RSC で React.cache を知らないと損する

前提

Next.js の App Router を使用している前提
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.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秒

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 を使用していないプロジェクトでは必ず使おう!

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?