我不明白为什么我的 setStock
函数没有更新状态,也没有导致重新渲染,而我还有其他几个函数工作得很好。
const addToStockOperation = async (addOperation) => {
const payload = {
...
};
const jwtToken = {
...
};
const addToStockOperationResult = await axios.put(`${apiEndpoint}/stock/addtoitem`, payload, jwtToken);
setStock((prevStock) => {
const indexOfModifiedStock = prevStock.findIndex((stock) => stock._id === addOperation.id);
console.log(prevStock[indexOfModifiedStock].operations.added.length);
prevStock[indexOfModifiedStock].operations.added = addToStockOperationResult.data.operations.added;
console.log(prevStock[indexOfModifiedStock].operations.added.length);
return prevStock;
});
};
两个控制台日志都确认 prevStock
的修改确实发生了,因为第二个 console.log 显示的长度与前一个长度相比增加了 +1,这表明 prevStock 的所需部分确实已更新,但是,不会导致重新渲染。
我还尝试制作 prevStock const stockCopy = {...prevStock};
的副本并修改副本并返回副本,但没有任何更改。
我也尝试过简单地 return 1;
只是为了看看是否会触发重新渲染,但仍然没有。
我还有其他一些类似的功能,它们运行良好,并且会按预期进行重新渲染:
这个在设置 products
时工作得很好:
const setProductsWrapper = async (product) => {
const addProductResult = await axios.post(
`${apiEndpoint}/product/one`,
payload,
token
);
addProductResult.data.name === product.name &&
setProducts((prevProducts) => [addProductResult.data, ...prevProducts]);
};
编辑:我发现了这个问题,愚蠢的我,修改副本后,stock 是一个数组 return [...stockCopy];
,有效。
答案 0 :(得分:2)
返回 prevStock
永远不会起作用,因为它是当前状态数组(即与它具有引用相等性)-您需要返回一个新数组以使新渲染成为触发。然而,突变状态似乎也出现了问题。
当您创建副本 const stockCopy = [...prevStock]
时,您正在途中,但问题是这仅将状态数组复制到一个深度级别。任何嵌套在其中的对象,如 .operations
,都将保持它们对原始状态数组中对象的引用相等性。
直接改变它们意味着当你返回你的副本时,任何依赖于这些子对象之间引用相等性差异的效果都不会运行,因为它们已经相等了。无需做任何区分。
要解决此问题,您必须深入复制树的相关部分:
setStock((prevStock) => {
const stockCopy = [...prevStock];
const stockIndex = stockCopy.findIndex((stock) => stock._id === addOperation.id);
stockCopy[stockIndex] = {
...stockCopy[stockIndex],
operations: {
...stockCopy[stockIndex].operations,
added: addToStockOperationResult.data.operations.added
}
};
return stockCopy;
});
当数据结构足够大时,这会变得非常烦人(并且可能很昂贵)。如果可以的话,最好避免在不可变状态下使用这样的结构。当然,通常情况并非如此,如果臃肿的代码开始成为问题,tools to help deal with immutability 可以减少它。