TanStack Query でアイテムを編集・削除時にキャッシュを書き換える

TanStack Query(旧:React Query)で一覧上のアイテムを編集・削除したとき、再フェッチせずキャッシュを直接書き換える。

開発環境

  • react: 18.2.0
  • @tanstack/react-query: 4.0.10

本文

queryClient.setQueryDataupdater に更新処理を渡すと更新されるので、useMutationonSuccess 内でその処理を行う。

注意:下記に実装を書くが私が作っている物の抜粋なので型などは書き換える必要がある

編集時

  • キャッシュを更新すべきクエリのキーは queryKey という変数に入っているものとする
  • onSuccess の引数の data には編集後のアイテムが入っているものとする
onSuccess: (data) => {
    const updater = (oldData: ArticlesQuery | undefined): ArticlesQuery | undefined => {
        // ありえない想定だが型のエラーを回避するために書いている
        if (!oldData || !oldData.articles || !oldData.articles.edges) {
            return oldData
        }
        // 編集したデータだけ新しい内容に更新
        const edges: (ArticleEdgeData | null)[] = oldData.articles.edges.map(
            (article: ArticleEdgeData | null) =>
            article && article.node?.id === data.updateArticle?.id
                ? { ...article, node: data.updateArticle }
                : article,
        )

        const res: ArticlesQuery = {
            ...oldData,
            articles: {
                ...oldData.articles,
                edges,
            },
        }
        return res
    }
    queryClient.setQueryData(useArticlesQuery.getKey(queryKey), updater)
}

削除時

  • キャッシュを更新すべきクエリのキーは queryKey という変数に入っているものとする
  • 削除したアイテムの id は id という変数に入っているものとする
 onSuccess: () => {
    const updater = (oldData: ArticlesQuery | undefined): ArticlesQuery | undefined => {
        // ありえない想定だが型のエラーを回避するために書いている
        if (!oldData || !oldData.articles || !oldData.articles.edges) {
            return oldData
        }
        // 削除したデータを除外
        const edges: (ArticleEdgeData | null)[] = oldData.articles.edges.filter(
            (article: ArticleEdgeData | null) => article && article.node?.id !== id,
        )
        const res: ArticlesQuery = {
            ...oldData,
            articles: {
                ...oldData.articles,
                edges,
            },
        }
        return res
    }
    queryClient.setQueryData(useArticlesQuery.getKey(queryKey), updater)
}

以上