• トップ
  • ブログ一覧
  • 【GraphQL】Apollo Clientのキャッシュ制御について【状態管理ライブラリ】
  • 【GraphQL】Apollo Clientのキャッシュ制御について【状態管理ライブラリ】

    ジョージ(エンジニア)ジョージ(エンジニア)
    2024.01.25

    IT技術

    はじめに

    GraphQLを学ぶにあたって、Apolloの公式チュートリアルが非常に有益でした。このチュートリアルは、GraphQLの基礎についても触れている為、GraphQLとApolloを実務に近い形でセットで学べる点が優れていると感じました。その中でも特に、キャッシュの制御については非常に勉強になった為、要点をまとめていきます。

    プロジェクトにApolloを導入検討している方、既に実務で使用している方、キャッシュ戦略を練る方などのお役に立てれば幸いです。いきなり本題読みたい方はこちら

    そもそもGraphQLとは?という方はこちらの記事
    GraphQLの基本的な操作についてはこちらの記事

    Apollo Clientとは

    JavaScript用の包括的な状態管理ライブラリで、ローカルとリモート両方のデータをGraphQLで管理できます。アプリケーションのデータのフェッチ(取得)や、キャッシュ、更新を行いながら、UIを自動的に更新できます。(公式参考)

    キャッシュの仕組み

    GraphQLでフェッチしたデータは、正規化後にインメモリのキャッシュに保存される為、Apollo Clientの初期設定時、cacheにInMemoryCasheを渡しておきましょう。

    1import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
    2
    3// Apollo clientの設定
    4const client = new ApolloClient({
    5  uri: 'http://localhost:4000', // GraphQLサーバーのURL
    6  cache: new InMemoryCache(), // キャッシュの設定
    7});

    Apollo Clientは、クエリ発行後にまずキャッシュを探して、データがある場合はそのまま返し、ない場合はサーバーにリクエストを送ってレスポンスを返す、という仕様になっています。その為、キャッシュにデータが既にある場合は、高速な画面表示が可能となっています。

    このデータフローについては、公式の図がわかりやすい為、一度ご覧になって下さい。

    キャッシュの制御方法〜fetchPolicy〜

    Apollo Clientでは、useQueryを用いてクエリを実行する際に、fetchPolicyというオプションでキャッシュの方法を制御することができます。

    1import { useQuery } from '@apollo/client';
    2
    3const { loading, error, data } = useQuery(MY_QUERY, {
    4  fetchPolicy: 'cache-and-network', // fetchPolicy記述例
    5});

    fetchPolicyオプションは以下の6つの中から、クエリごとのニーズに合わせて適切なものを選択できます。

    cache-first

    1fetchPolicy: 'cache-first'

    キャッシュにデータがあればそれを使用し、キャッシュにデータがなければGraphQLサーバーにクエリを実行し、キャッシュ後にそのデータを返します。クエリのレスポンス時間の短縮を重視したポリシーで、これがデフォルト値となっています。

    cache-only

    1fetchPolicy: 'cache-only'

    サーバーへのリクエストをせず、キャッシュのみにクエリを実行します。キャッシュ内にデータがない場合は、エラーがスローされます。サーバー側の変更は考慮せず、ユーザーに同じ情報を表示させ続けたい場合に使えるようです。

    cache-and-network

    1fetchPolicy: 'cache-and-network'

    クエリ実行後にキャッシュをクライアントに返却した後、同時にサーバーからデータフェッチして、キャッシュを更新します。この時キャッシュに変更があった場合は、更新後のキャッシュデータをクライアントに返します。高速なレスポンスが期待できる点とキャッシュのデータを最新のデータに保つことができる点が良いですね。

    network-only

    1fetchPolicy: 'network-only'

    キャッシュを通さずにGraphQLサーバーに対して直接クエリを実行し、フェッチしたデータでキャッシュを更新してそれを返します。常に最新のデータを表示したい場合などは効果的ですが、キャッシュが利用可能な時と比べるとレスポンス速度で劣ります。

    no-cache

    1fetchPolicy: 'no-cache'

    network-onlyと同じく、サーバーからデータフェッチして最新のデータを返すのみです。network-onlyとは違い、フェッチしたデータはキャッシュを更新もしませんし保存もされません。

    standby

    1fetchPolicy: 'standby'

    キャッシュに対してクエリが行われますが、フィールドの値が変更されても自動更新されません。クエリが待機状態になる為、refetchuseLazyQueryを使って任意のタイミングでの手動更新ができます。

    nextFetchPolicy

    クエリにはfetchPolicyだけではなく、nextFetchPolicyも指定することが可能です。これは例えば、最初のクエリはサーバーにリクエストして、2回目以降はキャッシュから読み込み可能、といった設定にもできます。

    1const { loading, error, data } = useQuery(MY_QUERY, {
    2  fetchPolicy: 'network-only', // 1回目のクエリ
    3    nextFetchPolicy: 'cache-first', // 2回目のクエリ 
    4});

    終わりに

    今回は、Apollo Clientという、GraphQLを使用してデータを管理するためのJavaScript状態管理ライブラリのキャッシュ制御についてのみ紹介致しましたが、これはApolloの機能のほんの一部に過ぎません。冒頭でも触れた通り、Apollo Clientは状態管理ライブラリであり、海外では記述の冗長なReduxに変わる可能性を秘めた状態管理ライブラリだという声も上がっているようでした。(参考)Apolloは学習コストが高い印象を受けましたが、プロジェクトへの導入を検討されている方やキャッシュ戦略を立てる方のお役に立てると幸いです。ここまで読んで頂きありがとうございました。

    ジョージ(エンジニア)

    ジョージ(エンジニア)

    おすすめ記事