はじめに
最近apolloの学習をしています。
apolloにはキャッシュの機能があり、これによって
リストにデータを追加/削除した時にリストが更新されない問題が起きる事があります。
本記事では、mutation後にキャッシュを書き換える方法について書いていきます。
キャッシュを書き換える2つの方法
- refetchを使う
- 自分で直接書き換える
他にもあるかも知れませんが、この記事では初学者の自分が知ってる方法2つを挙げます
「useGetListQuery()」などcodegenで生成したhooksを使っていますが、
useQuery(GET_LIST)などと同じです。
refetchを使う
const { data, refetch } = useGetListQuery();
hooksのresultとしてrefetchという関数を受け取る事ができます。
このrefetchを実行することで、もう一度同じリクエストをする事ができます。
(今回ならuseGetListQuery()を実行するのと同じ)
もう一度リクエストするので、data/キャッシュが更新されます。
アイテムを追加する処理の後で、refetchすることでキャッシュを更新する事ができます。
やり方①
await addItem() // リストにアイテムを追加するmutation
refetch()
※どちらも非同期処理なのでawaitをつけないと、mutationが終わる前にrefetchすることになってしまいます。
やり方②
onCompletedを使います。
const [addItem] = useAddItemMutation({
onCompleted() {
props.refetch();
},
})
(propsとしてrefetchを親から渡してきています。)
addItemが完了したタイミングで実行される様です。
しかし、自分がやったところ、できる時とできない時がありました。(謎い。。。)
自分で直接書き換える
キャッシュを自分で直接書き換えることもできます。
データを追加/削除したけどキャッシュが変わっていないという事は、
サーバーとクライアントのデータが違う状況です。
追加や削除したデータを使って、キャッシュに変更を加えて同じ状況にします。
(キャッシュの変更はサーバ側に影響しません。)
リストにデータを追加したい時
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のキャッシュになります。
return [...existing, newData];
元のキャッシュのデータにaddItemのデータを追加することで、キャッシュに追加する事に成功しました。
リストからデータを消したい時
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/