【问题标题】:React useState changes all elements in an array in array of objectsReact useState 更改对象数组中数组中的所有元素
【发布时间】:2021-10-13 17:12:43
【问题描述】:

我有 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

添加变体,更改价格添加另一个变体,您会看到我面临的所有问题。

【问题讨论】:

  • 在您的 CodeSandbox 示例中,您没有对产品进行深度复制,因此 variants 数组在对象之间共享。

标签: javascript reactjs react-hooks


【解决方案1】:

正因为如此:

 variant.price = e.target.value; // same issue with title

variant 对象引用在变体中共享,您正在直接对其进行修改。它是共享的,因为您在添加 variation 时使用 ... 创建了一个浅表副本。

解决办法如下:

您应该以 不可变 的方式更新特定的 variant 对象(在反应中,您应该始终以不可变的方式更新状态)。为此,您需要将其用作onChange for price:

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);
    }
}

这是onChangetitle:

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
        }]);
    }
}

【讨论】:

  • 完美运行!谢谢!
【解决方案2】:

首先,您没有将产品推向变体。你正在覆盖它。

使用 useState 将值推送到数组,

setVariations([...variations, product])

但是,如果您更改产品对象,变化也会发生变化,因为它是同一个对象。 (也许,react 不会重新渲染它,但相信我,它已经改变了。)如果你想保持不变,你需要创建新对象。

所以,

setProduct(data.data);
setVariations([...variations, {...data.data}]);

现在,您可以更改产品。变化不会改变。

【讨论】:

    【解决方案3】:

    这是因为你做了一个对象的浅拷贝。

    尝试这样做:

    setVariations([...variations, data.data,]);
    

    【讨论】:

      猜你喜欢
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 2021-02-13
      • 2020-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多