更改子组件状态会更改父组件props

IT技术 javascript reactjs redux immutability
2021-05-01 03:16:02

父组件是一个标题

子组件是一种表单,用于在触发 redux 操作的保存后更改出现在标题中的值。

我设置了子状态

constructor(props) {
    super(props);
    this.state = {
      object: { ...props.object },
      hidden: props.hidden,
    };
}

表单用于渲染 state.object 和修改 state.object。当我修改 state.object 时,来自父组件的 props 也会改变。

handleObjectChange = (event, key, subkey) => {
    console.log('props', this.props.object.params);
    console.log('state', this.state.object.params);
    event.preventDefault();
    const value = this.handlePeriod(event.target.value);
    this.setState((prevState) => {
      const object = { ...prevState.object };
      object[key][subkey] = value;
      return { object };
    });
}

控制台输出:

newvalueijusttyped
newvalueijusttyped

这种行为实际上一直到修改 redux 存储,而无需调度操作。

非常感谢这个问题的解决方案

更新:

将构造函数更改为此解决了问题

constructor(props) {
    super(props);
    this.state = {
      object: JSON.parse(JSON.stringify(props.object)),
      hidden: props.hidden,
    };
 }

为什么对象扩展运算符没有实现我想要实现的目标?

2个回答

Javascript 对象是通过引用分配的,所以当你这样做时

constructor(props) {
    super(props);
    this.state = {
      object: props.object,
      hidden: props.hidden,
    };
}

状态正在引用redux state object(如果它是一个 redux 状态)。所以现在当你使用

this.setState((prevState) => {
  const object = { ...prevState.object };
  object[key][subkey] = value;
  return { object };
});

尽管您会假设您已将对象值克隆到一个新对象中。然而,Spread 语法只对对象进行一级复制。

来自扩展语法 MDN 文档

注意:在复制数组时,Spread 语法有效地深入一层。因此,它可能不适合复制多维数组,如下例所示(与 Object.assign() 和 spread 语法相同)。

var a = [ 1 , [2], [3]]; var b = [...a]; b.shift().shift(); // 1 // 现在数组 a 也受到影响:[[], [2], [3]]

如此有效

object[key][subkey] = value;

直接在 redux 存储中更改值。

解决方案是创建一个嵌套的副本,如

  const object = { ...prevState.object,
                      [key]: {
                          ...prevState[key],
                          [subkey]: { ...prevState[key][subkey]}
                      }
                   };
  object[key][subkey] = value;

javascript 中的对象是“通过引用传递的”。

如果您将父项的 props 作为状态传递给子项,那么当您更改状态时,您实际上是在改变传递给它的相同对象。

使用 Object.assign() 创建数据的副本,然后再将其作为孩子状态的一部分。