React.js:更改子状态也会更改其父级传递的属性

时间:2018-07-25 21:23:01

标签: javascript html reactjs react-proptypes

我遇到的问题是,当我更改子组件的状态时,父组件的状态也会更改。我正将道具传递给孩子:

{this.state.users.map((user, index) => (
      <UserRow
        key={user.id}
        user={user}
        removeUser={this.removeUser}
        getUserInfo={this.getUserInfo}
        finishFunc={this.finishChanges}
      />
    ))}

然后将该道具分配给孩子的状态,如下所示:

state = {rowUser: this.props.user};

但是,当我更新此子状态时,似乎父状态会更新而无需重新呈现。

我通过道具而不是状态来显示信息

<div>{this.props.user.rules.length !== 0 ? this.props.user.rules.length : null}</div>

您可以看到初始显示here

当我单击“添加”或“删除”按钮时,状态显示会更改。您可以在图像here

中看到更改

我对改变孩子的状态如何更新父母的状态感到困惑,而又没有专门将数据传回父母。我也看不到它是如何改变显示的,因为我使用的是道具,而不是状态。

您可以在sandbox here中看到我的所有代码。每当您单击“添加新权限”和“删除权限”按钮时,都可以看到权限编号更改。

如何更改子状态时避免父状态自动更改?

2 个答案:

答案 0 :(得分:1)

问题:

问题在于我如何更改孩子的状态state = {rowUser: this.props.user}。我正在更改数据并像这样重置状态:

addPermission = () => {
  const tempUser = { ...this.state.rowUser };
  tempUser.permissions.push({
    property: "select permission",
    info: "type info..."
  });
  this.setState({ rowUser: tempUser });
  console.log("[UserEditingRow.js] permission added");
};

解决方案:

直接更改数据(即tempUser.permissions.push({...});)会导致问题。我使用React immutability helper帮助更具体地更新孩子的状态。因此,新功能将是:

addPermission = () => {
  this.setState(
    update(this.state, {
      rowUser: {
        permissions: {
          $push: [{property: 'select rule', info: ''}],
        },
      },
    }),
  );
  console.log('[UserEditingRow.js] rule added');
};

使用不变性助手设置状态允许子组件的状态发生更改而无需更新父组件的状态,从而解决了我的问题。

答案 1 :(得分:0)

检查完沙盒后,问题在于您正在将props.user分配给state.rowUser,并正在创建一个指向父组件值的指针。这意味着只要您更改this.state.rowUser,它实际上就会更新对props.user的引用。

解决方案

  1. 使用constructor()props.user绑定到state.rowUser,这是推荐的方法,此外,还可以使用传播运算符创建传递到组件中的对象的新实例,这将确保不会创建任何指针。
  

https://reactjs.org/docs/react-component.html#constructor

constructor(props){
  this.state = { rowUser: ...props.user }
}

另外

快速浏览沙箱,我还发现了其他一些反模式,这些反模式会给您带来一些问题。

  1. 您正在直接更新状态Line 76 to 84 in UserRow,然后调用setState,您应该做的是使用散布运算符克隆对象const tempUserRow = { ...this.state.userRow },然后操作对象并通过{{1}将其设置为状态}。这将确保您在setState中进行较浅的比较,然后重新呈现您的组件。
  2. 您使用的shouldComponentUpdate很好,但是您开箱即用shouldComponentUpdate并没有为您做任何事情,因此您应该将React.PureComponent更改为extends React.Component
  

https://reactjs.org/docs/react-api.html#reactpurecomponent