Apollo Client のキャッシュの仕組み

Apollo クライアントは、GraphQLクエリの結果を正規化してローカルのメモリ内に保存します。そして、メモリ内のクエリ結果をキャッシュとして利用します。 GraphQLクエリの実行時にクエリ結果がキャッシュにある場合は、ネットワークリクエストを省略して即時に応答できます。

Apollo Clietn のキャッシュの概要

公式ドキュメントのシーケンス図を引用しつつ、具体例を説明します。

GetBook(bookId: "5")のGraphQLクエリを実行するケースを考えてみましょう。

Apollo Client」の初回のGetBook(bookId: "5")のGraphQLクエリ実行時は「InMemoryCache」にBook:5のデータが存在しないため、「GraphQL Server」にクエリを実行して結果を取得します。そして、クエリ結果を「InMemoryCache」に正規化して保存し、「Apollo Client」にクエリ結果を返します。

初回リクエスト時のシーケンス図(引用元: https://www.apollographql.com/

その後、2回目以降のGetBook(bookId: "5")のGraphQLクエリを実行時は、「InMemoryCache」にBook:5のデータが存在するため、「GraphQL Server」にネットワークリクエストを実施せず、そのままキャッシュの値を「Apollo Client」に返します。

2回目以降のリクエスト時のシーケンス図(引用元: https://www.apollographql.com/

このように、キャッシュを有効に使うことで、アプリケーションは即時に応答することができます。しかし、キャッシュを使うことでメモリとサーバーの状態がずれてバグの温床にもなり得るので注意が必要です。

サポートされているFetch Policy

Apollo Client でサポートされているフェッチポリシーは次の6つになります。キャッシュの挙動に影響を与えるため、どのポリシーを使っているかを理解することが大切です。

ポリシー名 説明
cache-first (デフォルト) ネットワークリクエストの数を最小限に抑えることを優先している。
キャッシュに全てのフィールドのデータがあれば返す。なければGraphQLサーバーにクエリをリクエストする。クエリ結果をキャッシュする。
cache-and-network 高速な応答を提供しつつ、サーバーとローカルデータの一貫性を維持できる。
キャッシュとGraphQLサーバーの両方にクエリを実行し、サーバ側のクエリ結果をキャッシュする。
network-only サーバーとローカルデータの一貫性を常に保てる。
キャッシュを参照せず、GraphQLサーバーに常にリクエストする。クエリ結果はキャッシュする。
no-cache サーバーとローカルデータの一貫性を常に保つが、キャッシュは更新しない。
キャッシュを参照せず、GraphQLサーバーに常にリクエストする。クエリ結果はキャッシュしない。
cache-only キャッシュに全てのフィールドのデータがあれば返す。なければ、エラーをスローする。
standby cache-firstと同じロジックだが、フィールドが更新されても自動的に更新しない。

Fetch Policyの設定方法

フェッチポリシーの設定方法は、主に次の2つがあります。

  • new ApolloClient時にfetchPolicyを指定
  • useQueryfetchPolicy を指定

new ApolloClient時にfetchPolicyを指定」するとデフォルトのフェッチポリシーを指定することができます。(参考: class Apollo Client

const client = new ApolloClient({
  uri: 'https://flyby-router-demo.herokuapp.com/',
  cache: new InMemoryCache(),
  defaultOptions: {
    query: {
      fetchPolicy: 'cache-first',
    },
    watchQuery: {
      fetchPolicy: 'cache-and-network'
    },
  },
});

また、「useQueryfetchPolicy を指定」すると、個別でフェッチポリシーを指定できます。

const { loading, error, data } = useQuery(GET_TODOS, {
  fetchPolicy: 'network-only', // キャッシュを利用せずGraphQLサーバーに常にリクエスト。クエリ結果はキャッシュする
});

Apollo Client のキャッシュを可視化する

ブラウザ拡張の Apollo Client Devtools を利用することで、キャッシュを可視化できます。

また、キャッシュは正規化されて格納されます。How is data stored? でキャッシュの構造について理解を深めることができます。

Apollo Client のキャッシュを操作する

Apollo Client のキャッシュを直接操作することができます。

メソッド 説明
readQuery / writeQuery / updateQuery GraphQLのクエリ結果を取得・変更できる
readFragment / writeFragment / updateFragment / useFragment フラグメントの値を取得・変更できる
cache.modify キャッシュの値を直接変更できる

より詳細は Reading and writing data to the cacheを参照ください。