4
0

More than 3 years have passed since last update.

【apollo client】mutation後にキャッシュを書き換える

Last updated at Posted at 2021-06-07

はじめに

最近apolloの学習をしています。

apolloにはキャッシュの機能があり、これによって
リストにデータを追加/削除した時にリストが更新されない問題が起きる事があります。

本記事では、mutation後にキャッシュを書き換える方法について書いていきます。

キャッシュを書き換える2つの方法

  1. refetchを使う
  2. 自分で直接書き換える

他にもあるかも知れませんが、この記事では初学者の自分が知ってる方法2つを挙げます

「useGetListQuery()」などcodegenで生成したhooksを使っていますが、
useQuery(GET_LIST)などと同じです。

refetchを使う

List.tsx
const { data, refetch } = useGetListQuery();

hooksのresultとしてrefetchという関数を受け取る事ができます。
このrefetchを実行することで、もう一度同じリクエストをする事ができます。
(今回ならuseGetListQuery()を実行するのと同じ)

もう一度リクエストするので、data/キャッシュが更新されます。

アイテムを追加する処理の後で、refetchすることでキャッシュを更新する事ができます。

やり方①

Item.tsx
await addItem() // リストにアイテムを追加するmutation
refetch()

※どちらも非同期処理なのでawaitをつけないと、mutationが終わる前にrefetchすることになってしまいます。

やり方②

onCompletedを使います。

Item.tsx

const [addItem] = useAddItemMutation({
  onCompleted() {
      props.refetch();
    },
})

(propsとしてrefetchを親から渡してきています。)
addItemが完了したタイミングで実行される様です。
しかし、自分がやったところ、できる時とできない時がありました。(謎い。。。)

自分で直接書き換える

キャッシュを自分で直接書き換えることもできます。

データを追加/削除したけどキャッシュが変わっていないという事は、
サーバーとクライアントのデータが違う状況です。

追加や削除したデータを使って、キャッシュに変更を加えて同じ状況にします。
(キャッシュの変更はサーバ側に影響しません。)

リストにデータを追加したい時

Item.tsx
const [addItem] = useAddItemMutation({
    update(cache, data) {
      const newData = data.data?.addItem;
      cache.modify({
        fields: {
          getList(existing = []) {
          const newItemRef = cache.writeFragment({
              data: newData,
              fragment: gql`
                fragment AddItem on ItemModel {
                  id
                  name
                }
              `,
            });
            return [...existing, newItemRef];
          },
        },
      });
    },
  });

updateオプションを使います。

cacheにはキャッシュの情報が入ります。
dataには、addItemを実行したデータが入ります。
(任意の名前をつける事ができます。)

一度console.logでcacheやdataを見てみることをオススメします。

existingには、getListの配列が入ります。
ここには、参照が入っています
(existingにも任意の名前をつける事ができます。)

追加したアイテムの参照を作りexistingと一緒にreturnしています
returnの値がgetListのキャッシュになります。

Item.tsx
return [...existing, newData];

元のキャッシュのデータにaddItemのデータを追加することで、キャッシュに追加する事に成功しました。

リストからデータを消したい時

Item.tsx
const [deleteItem] = useDeleteItemMutation({
    update(cache, data) {
      const newData = data.data?.addItem;
      cache.modify({
        fields: {
          getList(existing = [], { readField }) {
            const newItemList = existing.filter((item: any) => {
              return readField("id", item) !== data.data?.deleteItem?.id;
            });
            return [...newGroupList];
          },
        },
      });
    },
  });

データの追加とほとんど同じです。
データの削除では、削除したアイテムと同じidを持つデータをキャッシュのリストから削除しています。
readFieldを使うことで、キャッシュされてるアイテムのフィールドにアクセスできます。
filterを使って順番に確認をしていき、同じidを持たないListを新しく作成し、それをreturnしています。

これで、キャッシュの更新をする事ができました。

もし間違っている所、おかしな所があれば教えていただけると幸いです。

参考文献

https://www.apollographql.com/docs/react/caching/cache-configuration/
https://www.apollographql.com/docs/react/data/mutations/
https://www.apollographql.com/docs/react/data/queries/

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0