Open9

AppRouter+ApolloClientのキャッチアップ

はやせはやせ

getClientの内部実装

  • Reactのcacheでメモ化している
  • cacheについて
    • メモ化した関数を初回実行時に実行する
    • それ以降はキャッシュされた値を使用する
    • SCでのみ動作
    • メモ化された関数をコンポーネント外で呼び出すとキャッシュは使用されない
    • https://ja.react.dev/reference/react/cache
function makeGetClient<
  AC extends Promise<ApolloClient<any>> | ApolloClient<any>,
>(makeClient: () => AC): () => AC {
  function makeWrappedClient() {
    return { client: makeClient() };
  }

  // ここでメモ化
  const cachedMakeWrappedClient = cache(makeWrappedClient);

  function getClient() {
    if (arguments.length) {
      ...
    }
    // ここで呼び出し、getClientはコンポーネント内部で呼び出されるので、キャッシュがあればキャッシュが使われる
    const wrapper = cachedMakeWrappedClient();
    if (seenWrappers && seenClients) {
      ...
    }
    return wrapper.client;
  }
  return getClient;
}

https://github.com/apollographql/apollo-client-integrations/blob/main/packages/client-react-streaming/src/registerApolloClient.tsx#L116-L164

はやせはやせ

なぜClientをラップしているか

  • リクエストごとに別のインスタンスが使われている必要がある
  • Clientだけを保持してseenClients.has(wrapper.client)をしても、同一インスタンス化は判別がつくが、同一リクエストかの判別はつかない
  • wrapperを作ることで、そのwrapperはリクエストごとに一意になるので、同一リクエストかどうかの判別をつけられる
  • ちなみにseenWrappersseenClientsはここでしか使われていないので、warningを出すためだけにある仕組みっぽい
  • これによってNext.jsのfetchと同じような挙動を再現してるのかな

https://github.com/apollographql/apollo-client-integrations/blob/main/packages/client-react-streaming/src/registerApolloClient.tsx#L142-L160

はやせはやせ

fetchOptionsについて

  • fetchOptionsにNext.jsのfetchに渡すオプションを指定できる
  const {data} = await getClient().query({
    query: userQuery,
    context: {fetchOptions: {next: {revalidate: 5}}},
  });
  • fetchOptionsに渡した値はfetchに渡される

fetchOptions Any overrides of the fetch options argument to pass to the fetch call

https://github.com/apollographql/apollo-client/blob/4e2e3e8ed5461a9fb31ba0fa2d17db39fbba564c/docs/source/api/link/apollo-link-http.mdx#fetchoptions-1

はやせはやせ
  • なんでそもそもリクエストごとのキャッシュなのか
    • セキュリティ観点かな、別リクエストで同じインスタンスだとデータ漏洩のリスクがある
    • Next.jsは大丈夫なんだろうか
      • Next.jsのRequest MemoizationもReactのcacheを使っているので、リクエストごとにキャッシュは無効化されるので大丈夫
  • 別ページから戻ったらどうなるか、その時の挙動がfetchOptionという予測
  • Next.jsのキャッシュはページを跨いだらどうなるか
    • 設定次第、リクエストごとのキャッシュはリクエストごとに無効化されるので、セキュリティ的な観点は大丈夫そう
はやせはやせ

Request Memoization

  • 同一リクエストで同じリクエストは重複してリクエストされない
  • これはReactの機能で、GETにのみ機能する
  • 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.
  • 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.

https://nextjs.org/docs/app/deep-dive/caching#request-memoization

  • これはGraphQLには適用されない、なのでapollo-client-integrationsのようなものが必要