apolloの4つの fetchPolicy を理解する

## はじめに

apolloの4つの fetchPolicy を勉強していきます。

## 最終的なゴール

以下のような構成のアプリを作ることです。

![スクリーンショット 2021-10-18 17.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/e8a9a2e1-2723-4fec-77ef-be3b9eefdd81.png)

### 目的

- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上

## 前回のおさらい

HasuraのGraphQlサーバからデータフェッチした後`ComponentA`ではフェッチしたデータを表示させましたが

`ComponentB`では、Apolloが作成したキャッシュのデータを取得する実装をしました。

![スクリーンショット 2021-11-03 21.21.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/7da9815a-ff5c-8dd5-0e82-b78b6cfe7ed2.png)

詳細👇

https://qiita.com/ryosuketter/items/22e7bb02a1b17adad4ff

## なぜApolloのキャッシュ機構を学ぶのか？

ユーザーにとって良いWeb閲覧体験をしてもらうためです。そのために、パフォーマンスチューニングの理解が必要です。

Apollo Clientは不要な通信処理を防ぐため、様々なキャッシュ機構を備えています。

クエリの結果をブラウザのメモリに保存することで、サーバーからデータを取らずにメモリ上のデータを使用することができます。

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

## apolloの4つの fetchPolicy を勉強

前回の記事では、`'network-only'`だけ学びました。

```ts
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'network-only',
})
```

今回は、コメントした以下も含めて見ていきます。

```ts
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'network-only',
//fetchPolicy: 'cache-and-network',
//fetchPolicy: 'cache-first',
//fetchPolicy: 'no-cache', 
})
```

### fetchPolicy: 'cache-first'

デフォルトの場合、こちらのfetchPolicyになります。

```ts
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'cache-first',
})
```

なので、以下と同じ意味です。

```ts
const { data } = useQuery<GetUsersQuery>(GET_USERS)
```

意味は、データがキャッシュにある場合は、そこから取得するけど、無いならGraphQlからデータフェッチします。

仮に、Hasura側で新たに`User`のデータが作られても、GraphQlからデータフェッチせず、ブラウザのメモリから取得するので、新規作成ユーザーは表示されません。

なので、更新性の高いことが価値のあるWebページでは、このfetchPolicyは採用しない方がいいでしょう。

### fetchPolicy: 'no-cache'

キャッシュを使用しないポリシーです。
取得したデータをブラウザ上のメモリに保存（キャッシュ）しないのが特徴です。

クエリを投げた時に、キャッシュのデータを確認せずに、サーバーからデータを取ってきます。

```ts:pages/hasura-main.tsx
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'no-cache',
})
```

ブラウザ確認してみましょう。

![022e469508a54008f17ba4facd073c3b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/2da54007-a48e-8c61-709c-9408af6acdf5.gif)

`hasura-sub`の方が何も表示されなくなりました。

なぜなら、`hasura-sub`は、キャッシュからデータを取得するクエリにし（`GET_USERS_LOCAL`）

`fetchPolicy: 'no-cache'`は、キャッシュデータを作らないようにしているからです。

```ts:pages/hasura-sub.tsx
const { data } = useQuery<GetUsersQuery>(GET_USERS_LOCAL)
```

gif画像を見ると、Backして再度`hasura-main`を見たら、またGraphQlへデータフェッチしていることがわかります。

`fetchPolicy: 'no-cache'`は、毎回サーバーサイド（GraphQl）にデータフェッチしていることがわかります。

npmの`axios`でREST APIでデータ取得するイメージと似た感じかもしれません。

https://github.com/axios/axios

### fetchPolicy: 'network-only'

サーバーのデータのみを使用するポリシーです。常に最新のデータを扱うことができます。

```ts:pages/hasura-main.tsx
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'network-only',
})
```

ブラウザ確認してみましょう。

![ec851185a88b0f74cf250b20b9d31018.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/30fc8267-c8aa-7448-d8a3-93113d861e17.gif)

こちらは、キャッシュしてそうですね。

そして、これなら、毎回Hasuraからのデータを読みに行っているので、最新のデータを取得できそうですね。

### fetchPolicy: 'cache-and-network'

メモリ上のデータとサーバーのデータ両方を使用するポリシーです。レスポンスが早いのと、データの更新を頻繁に行うのが特徴です。

```ts:pages/hasura-main.tsx
const { data } = useQuery<GetUsersQuery>(GET_USERS, {
  fetchPolicy: 'cache-and-network',
})
```

これもサーバーサイドへ最新のデータを取得しにいくという点では

`fetchPolicy: 'network-only'`と同じですが、取得中に既存のキャッシュがあればそれを表示し、

サーバからデータが取得でき次第、それを表示するという点が違います。

少し詳しく話すと。以下のような順番です。

- 1. クエリを投げた時に、キャッシュ上にデータがあるかを確認
- 2. キャッシュ上にデータがある場合は、キャッシュのデータを返す
- 3. サーバーからデータを取ってくる
- 4. サーバーから取ってきたデータをメモリ上に保存
- 5. クエリの結果を返す

どのページ、どのWebアプリケーションも基本的には、ポリシーは、`fetchPolicy: 'network-only'`で問題ないかと思います。

### 参考

https://www.apollographql.com/docs/react/data/queries/#supported-fetch-policies

今日のところは以上です。

次の記事では、Hasuraと連携させたCRUDの操作を紹介します。

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103