【问题标题】:Changing a child components state changes the parent components props更改子组件状态会更改父组件道具
【发布时间】:2017-07-26 05:14:32
【问题描述】:

父组件是一个header

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

我用

设置子状态
constructor(props) {
    super(props);
    this.state = {
      object: { ...props.object },
      hidden: props.hidden,
    };
}

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

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

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

【问题讨论】:

  • 展开运算符只克隆第一层。所以对象内部的对象仍然是通过引用传递的。使用ImmutableJS 以获得更好的性能

标签: javascript reactjs redux immutability


【解决方案1】:

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

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

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

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

虽然您会假设您已将对象值克隆到一个新对象中。然而,Spread 语法只对对象进行一级副本。

来自Spread Syntax MDN docs

注意:传播语法在复制一个 大批。因此,它可能不适合复制多维 如下例所示的数组(与 Object.assign() 和传播语法)。

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

这么有效

object[key][subkey] = value;

直接在 redux store 中更改值。

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

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

【讨论】:

    【解决方案2】:

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

    如果您将父母的道具作为状态传递给孩子,那么当您更改状态时,您实际上是在改变传递给它的同一个对象。

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

    【讨论】:

    • 感谢您的建议。在构造函数中使用 Object.assign() 和扩展运算符并没有解决问题。使用 JSON stringily 然后解析确实解决了这个问题。希望对此行为进行任何澄清。
    • Object.assign 不会进行深度克隆。 JSON.stringify 可以,但速度很慢。更好地使用 ImmutableJS。
    • 啊,这很有趣。文档并没有真正谈论仅在任何地方进行浅克隆的传播。会记住的。
    • 只是顺便提了一下。解释了我曾经遇到的传播问题。
    • 是的,猜猜是时候实现不可变了。谢谢你的解释。
    猜你喜欢
    • 1970-01-01
    • 2019-11-26
    • 2019-10-04
    • 1970-01-01
    • 2021-01-28
    • 1970-01-01
    • 2018-11-03
    • 2023-03-29
    • 2019-07-12
    相关资源
    最近更新 更多