🔖

Apollo Client のデフォルトで設定されている fetch policy を変更する

2022/09/18に公開

はじめに

Apollo Client はクエリーなどでデータを取得した時に、結果を自動でキャッシュするようになっています。その後、再度同じクエリーを実行するとサーバーサイド側にはクエリーを投げず、キャッシュされているデータを返します。

https://www.apollographql.com/docs/react/data/queries/#caching-query-results

これにより、レスポンスの高速化やサーバーサイド側の負荷を下げるなどのメリットはあるものの、再 fetch されずデータがうまく反映されないなどの問題が発生するリスクが高まります。

特にプロジェクト立ち上げ時などは、パフォーマンスよりもまずは正しく動くことを優先したい!というケースもあると思うので、キャッシュを使用しないのも選択肢の1つかなと思います。(Apollo を使う旨味が減りそうですが...)

キャッシュを使用するか否かは fetch policy によって変更できます。
https://www.apollographql.com/docs/react/data/queries/#setting-a-fetch-policy

本記事では、サポートされている fetch policy を見ていき、最終的にはデフォルトの fetch policy を変更します。

筆者は Apollo Client を使い始めてまだ日が浅いので、認識に誤りがあるかもしれないです。その時は優しくコメントいただけると助かります🙏

サポートされている fetch policy を見ていく

cache-first

デフォルトの fetch policy なので、設定を変更していなければ cache-first が設定されているはずです。キャッシュに対してクエリーし、キャッシュがなければサーバーサイド側にクエリーします。名前の通りキャッシュを優先します。

cache-only

先にキャッシュに対してクエリーするところまでは cache-first と同じですが、キャッシュがなかった時に例外を発生させるところが異なります。

初回のクエリー実行時はキャッシュがないので、必ずエラーになってしまうのでは?と思いましたが、nextFetchPolicy を使用することで、初回のクエリー、2回目以降のクエリーでそれぞれ fetch policy を設定できるようです。
https://www.apollographql.com/docs/react/data/queries/#nextfetchpolicy

cache-and-network

キャッシュとサーバーサイド側の両方に対してクエリーします。キャッシュがあれば瞬時に表示できますし、サーバーサイド側にもクエリーを投げるのでデータの整合性も取れます。ただ、キャッシュの内容とレスポンスの結果が異なっていた場合はキャッシュの内容を表示 → レスポンスの結果を表示と内容が変わるので多少ちらつきます。

network-only

キャッシュに対してクエリーせず、サーバーサイド側に対してクエリーします。また、キャッシュは参照しないものの、クエリー結果はキャッシュします。キャッシュする理由はあまり把握できていないですが、nextFetchPolicy で記載されているサンプルのように cache-only と組み合わせて使いたい場面があるんですかね。network-only は整合性を保てるメリットはあるものの、都度サーバーサイドに対してクエリーするので、キャッシュを使用する場合と比較するとパフォーマンスは悪くなります。

no-cache

キャッシュに対してクエリーせず、サーバーサイド側に対してクエリーするところまでは network-only と同じですが、クエリー結果をキャッシュしないところが異なります。nextFetchPolicy などでキャッシュを使用しないなら network-only ではなく、no-cache を使用するのが良さそうかなと思いました。

standby

先にキャッシュに対してクエリーするところまでは cache-first と同じですが、フィールドが更新された時にサーバーサイド側にクエリーされないところが異なるようです。正直使い所はあまりイメージできていません...

デフォルトの fetch policy を変える

defaultOptions の watchQuery で fetch policty を指定することで、すべてのクエリーに適用できます。
https://www.apollographql.com/docs/react/api/core/ApolloClient/#defaultoptions

今回は下記のようにキャッシュを無効にしてみました。

export default new ApolloClient({
  ...
  defaultOptions: {
    watchQuery: {
      fetchPolicy : 'no-cache'
    }
  }
}

終わりに

今回は安全側に倒してキャッシュを無効にしましたが、これだと Apollo の旨味が減ってしまうので良い方法を模索していきたいなーと思っています。(cache-and-network は良い落とし所かなとも思ったのですが、どうしてもちらつきが気になり...)

Discussion