>我有 2 种状态产品和变体,我调用 API 并将两种状态的值设置为 API 响应。
我希望产品状态保持原样,而不是更新
const [product, setProduct] = useState({} as any);
const [variations, setVariations] = useState([] as any);
useEffect(() => {
const getProduct = async () => {
const data = await axios.get("/products?id=4533843820679");
console.log(data);
setProduct(data.data);
// @ts-ignore
setVariations([data.data]);
};
getProduct();
}, []);
作为回报,我映射变体数组并返回标题、价格和添加变体的按钮的输入。添加变体会将另一个产品添加到变体数组。所以它只是将产品推向变体。
然后,我输入了变体中的标题和变体中的价格。问题出在 onChange 上。
当我更改变体中一个元素的价格时,它会更改所有元素的价格,并且还会更改 PRODUCT 状态的价格。
代码可以在这里找到:https://codesandbox.io/s/smoosh-firefly-6n747?file=/src/App.js
添加变体,更改价格添加另一个变体,您将看到我面临的所有问题。
正是因为这个:
variant.price = e.target.value; // same issue with title
variant
对象引用在变体之间共享,您直接对其进行修改。之所以共享它,是因为您在添加variation
时使用...
制作了该副本的浅拷贝。
这是解决方案:
你应该以不可变的方式更新特定的variant
对象(在 react 中,你应该始终以不可变的方式更新状态)。为此,您需要将其用作price
的onChange
:
onChange = {
(e) => {
let updated = variations.map((x) => {
if (x.id === variation.id) {
return {
...x,
variants: x.variants.map((y) => {
if (y.id === variant.id) {
return {
...y,
price: e.target.value
};
}
return y;
})
};
}
return x;
});
setVariations(updated);
}
}
这为onChange
title
:
onChange = {
(e) => {
let updated = variations.map((x) => {
if (x.id === variation.id) {
return {
...x,
title: e.target.value
};
}
return x;
});
setVariations(updated);
}
}
注意,但变体的 ID 必须不同。出于测试目的,您可以在添加新变体时将其用作点击处理程序:
onClick = {
() => {
setVariations((prev) => [...prev, {
...product,
id: Math.floor(Math.random() * 1000) // for testing
}]);
}
}
首先,您不会将产品推向变体。您正在覆盖它。
要使用 useState 将值推送到数组,
setVariations([...variations, product])
但是,如果您更改产品对象,变体也会更改,因为它是相同的对象。(也许,反应不会重新渲染它,但相信我,它被改变了。如果你想保持它不变,你需要创建新对象。
所以
setProduct(data.data);
setVariations([...variations, {...data.data}]);
现在,您可以更改产品。变体不会更改。
这是因为您做了对象的浅表副本。
尝试这样做:
setVariations([...variations, data.data,]);