这个问题我已经处理了一段时间了,但还是解决不了。
我使用React-query作为服务器状态管理库,并尝试在发生变化时使UI状态与服务器状态同步,因为我可以使用变化响应来避免新的API调用,所以我使用了React-query提供的setQueryData特性。
问题是,当一个变异成功时,旧数据被正确地修改了(我可以在React查询DevTools中看到它),但是使用它的组件没有被重新呈现,这使得我的UI状态与我的服务器状态不同步(好吧,至少用户看不到更新)。
让我展示一些代码,希望有人能给我一些见解。Component using the query:
const Detail = ({ orderId }) => {
const { workGroups } = useWorkGroups();
const navigate = useNavigate();
const queryClient = useQueryClient();
const orderQueries = queryClient.getQueryData(["orders"]);
const queryOrder = orderQueries?.find((ord) => ord.id === orderId);
// more code
Component mutating the query
:
const Deliver = ({
setIsModalOpened,
artisan,
index,
queryQuantity,
queryOrder,
}) => {
const [quantity, setQuantity] = useState(() => queryQuantity);
const { mutate: confirmOrderDelivered } = useMutateOrderDeliveredByArtisan(
queryOrder.id
);
const onSubmit = () => {
confirmOrderDelivered(
{
id: queryOrder.artisan_production_orders[index].id,
artisan: artisan.user,
items: [
{
quantity_delivered: quantity,
},
],
},
{
onSuccess: setIsModalOpened(false),
}
);
};
// more code
Now the mutation function (ik it's a lot of logic but I dont' want to refetch the data using invalidateQueries since we're dealing with users with a really bad internet connection). Ofc you don't need to understand each step of the fn but what it basically does is update the old queried data. In the beginning I thought it was a mutation reference problem since React using a strict comparison under the hood but I also checked it and It doesn't look like it's the problem.
:
{
onSuccess: (data) => {
queryClient.setQueryData(["orders"], (oldQueryData) => {
let oldQueryDataCopy = [...oldQueryData];
const index = oldQueryDataCopy.findIndex(
(oldData) => oldData.id === orderId
);
let artisanProdOrders =
oldQueryDataCopy[index].artisan_production_orders;
let artisanProductionOrderIdx = artisanProdOrders.findIndex(
(artProdOrd) => artProdOrd.id === data.id
);
artisanProdOrders[artisanProductionOrderIdx] = {
...artisanProdOrders[artisanProductionOrderIdx],
items: data.items,
};
const totalDelivered = artisanProdOrders.reduce((acc, el) => {
const delivered = el.items[0].quantity_delivered;
return acc + delivered;
}, 0);
oldQueryDataCopy[index] = {
...oldQueryDataCopy[index],
artisan_production_orders: artisanProdOrders,
items: [
{
...oldQueryDataCopy[index].items[0],
quantity_delivered: totalDelivered,
},
],
};
return oldQueryDataCopy;
});
},
onError: (err) => {
throw new Error(err);
},
}
最后但并非最不重要:我已经检查了是否正确修改了oldQueryData(控制台登录到突变响应中的onSuccess fn),并且正如我之前所说的,在React-query DevTools中正确修改了数据。
我知道这是很多代码,问题似乎很复杂,但我真的相信这可能是一件很容易的事情,我没有指出,因为我已经很累了。
谢谢!
2条答案
按热度按时间uemypmqf1#
嗯,我修复了它在最坏的可能的方式imho,所以我会回答这个问题,但我真的很想读你的想法。
看起来,只有当变异函数位于我们实际想要重新呈现的组件中时,在预期查询上设置的新查询数据才重新呈现组件。
考虑到这一点,我所做的只是将我的变异函数放在父组件中,并通过子组件传递它。
大概是这样的
First child
:Component that actually needs the mutation fn
:ryhaxcpt2#
你不能变异任何 prop 。
你总是需要创建新版本的对象和 prop ,并使用解构。