我目前正在使用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,
};
};
1条答案
按热度按时间yhxst69z1#
这里是工作解决方案