使用tRPC与React-Query实现乐观更新时出现数据闪烁问题
问题:tRPC useMutation乐观更新出现数据闪烁
我用tRPC的useMutation结合React-Query实现乐观更新,功能整体正常,但遇到一个问题:更新数据时,新列表会快速显示出来,但几毫秒后又恢复为旧值,最终才重新显示新值。以下是我的实现代码:
import { api } from "@/utils/api"; import type { Category } from "@prisma/client"; export const useCategoryActions = () => { const utils = api.useContext(); //Queries const list = api.category.list.useQuery(); // Mutations const update = api.category.update.useMutation({ onMutate: (variables) => { // Cancel any outgoing refetches (so they don't overwrite(race condition) our optimistic update) void utils.category.list.cancel(); const previousQueryData = utils.category.list.getData(); const newCategory: Category = { id: crypto.randomUUID(), name: variables.name, slug: variables.name, createdAt: new Date(), updatedAt: new Date(), }; utils.category.list.setData(undefined, (oldQueryData) => { if (oldQueryData) { const filteredData = oldQueryData.filter((item) => item.slug !== variables.slug) ?? []; const elementIndex = oldQueryData.findIndex((item) => item.slug === variables.slug) ?? -1; filteredData.splice(elementIndex, 0, newCategory); return filteredData; } }); // return will pass the function or the value to the onError third argument: return () => utils.category.list.setData(undefined, previousQueryData); }, onError: (error, variables, rollback) => { // If there is an errror, then we will rollback if (rollback) { rollback(); console.log("rollback"); } }, onSettled: async (data, variables, context) => { await utils.category.list.invalidate(); }, }); return { list, update, }; };
我尝试了一个潜在解决方案,但似乎无效,可能是实现方式有误:
import { useRef } from "react"; import { api } from "@/utils/api"; import type { Category } from "@prisma/client"; export const useCategoryActions = () => { const utils = api.useContext(); const mutationCounterRef = useRef(0); //Queries const list = api.category.list.useQuery(); // Mutations const update = api.category.update.useMutation({ onMutate: (variables) => { // Cancel any outgoing refetches (so they don't overwrite(race condition) our optimistic update) void utils.category.list.cancel(); const previousQueryData = utils.category.list.getData(); const newCategory: Category = { id: crypto.randomUUID(), name: variables.name, slug: variables.name, createdAt: new Date(), updatedAt: new Date(), }; utils.category.list.setData(undefined, (oldQueryData) => { if (oldQueryData) { const filteredData = oldQueryData.filter((item) => item.slug !== variables.slug) ?? []; const elementIndex = oldQueryData.findIndex((item) => item.slug === variables.slug) ?? -1; filteredData.splice(elementIndex, 0, newCategory); return filteredData; } }); // Increment the mutation counter mutationCounterRef.current++; // return will pass the function or the value to the onError third argument: return async () => { // Decrement the mutation counter mutationCounterRef.current--; // Only invalidate queries if there are no ongoing mutations if (mutationCounterRef.current === 0) { utils.category.list.setData(undefined, previousQueryData); await utils.category.list.invalidate(); } }; }, onError: async (error, variables, rollback) => { // If there is an errror, then we will rollback if (rollback) { await rollback(); console.log("rollback"); } }, onSettled: async (data, variables, context) => { // Decrement the mutation counter mutationCounterRef.current--; // Only invalidate queries if there are no ongoing mutations if (mutationCounterRef.current === 0) { await utils.category.list.invalidate(); } }, }); return { list, update, }; };
内容的提问来源于stack exchange,提问作者John John
相关产品推荐
相关产品推荐

