简体   繁体   English

ReactJS:setState 中的对象更新但未反映在 UI 中

[英]ReactJS : Object updating in setState but not reflecting in UI

I am new to ReactJS.我是 ReactJS 的新手。 When I click on the button, the call will go from createTablesam.js to index.js to update the object.当我单击按钮时,调用将从createTablesam.js转到index.js以更新对象。 the object is updated successfully in setState but not updating in UI.对象在setState更新成功,但未在 UI 中更新。 If I again the button again the object is updating but UI is not updating.如果我再次按下按钮,则对象正在更新但 UI 未更新。

 const PureComponent = React.PureComponent; class Index extends PureComponent { constructor() { super(); this.state = { userValues: [ { name: "Mani", age: 23, skill: "Java" }, { name: "Vel", age: 23, skill: "react" } ] }; this.addRow = this.addRow.bind(this); } addRow() { let newdetails = { name: "ManiVEL", age: 25, skill: "REACT JS" }; let userValues = this.state.userValues; userValues.push(newdetails); this.setState({ userValues }); } render() { return ( <CreateTablesam addtable={this.addRow} tabelDeatils={this.state.userValues} ></CreateTablesam> ); } } class CreateTablesam extends PureComponent { state = { tableCopy: this.props.tabelDeatils }; render() { const createRow = this.state.tableCopy.map(per => ( <tr key={per.name}> <td>{per.name}</td> <td>{per.age}</td> <td>{per.skill}</td> </tr> )); return ( <div> <table> <thead> <tr> <td>Name</td> <td>Age</td> <td>skills</td> </tr> </thead> <tbody>{createRow}</tbody> </table> <button onClick={this.props.addtable}>CLICK</button> </div> ); } } ReactDOM.render(<Index />, document.getElementById("root"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>

what mistake have I done?我犯了什么错误?

You need to improve the way you are updating array in state.您需要改进更新状态数组的方式。 As mentioned in comment section, please read Correct modification of state arrays in ReactJS如评论部分所述,请阅读ReactJS 中状态数组的正确修改

In your case, it would be: this.setState({ userValues: [...this.state. userValues, newelement] })在您的情况下,它将是: this.setState({ userValues: [...this.state. userValues, newelement] })

Once you have above point right, you need to improve key handling part.一旦你正确了,你需要改进关键处理部分。 Please read: Understanding unique keys for array children in React.js请阅读: 了解 React.js 中数组子项的唯一键

Reason for it is that data in table have same key key={per.name} .原因是表中的数据具有相同的键key={per.name} Since you are always adding the same records, name property will remain same.由于您总是添加相同的记录,因此name属性将保持不变。 So, <tr key={per.name}> key will remain same.因此, <tr key={per.name}>键将保持不变。 Try adding different object(at least different name) to table.尝试向表中添加不同的对象(至少是不同的名称)。

You're directly mutating the state in addRow .你直接变异的状态addRow Either make a copy of the userValues or use the functional form of setState :要么制作userValues的副本,要么使用setState的函数形式:

addRow() {
  let newdetails = {
    name: "ManiVEL",
    age: 25,
    skill: "REACT JS"
  };

  this.setState(state => {
    return {
      userValues: [...state.userValues, newdetails]
    }
  });
}

// or

addRow() {
  let newdetails = {
    name: "ManiVEL",
    age: 25,
    skill: "REACT JS"
  };

  this.setState({
      userValues: [...this.state.userValues, newdetails]
  });
}

Edit: you also need to use the props directly, instead of assigning them to state in your child component:编辑:您还需要直接使用道具,而不是将它们分配给您的子组件中的状态:

class CreateTablesam extends PureComponent {
  render() {
    const createRow = this.props.tabelDeatils.map((per, i) => (
      <tr key={i}>
        <td>{per.name}</td>
        <td>{per.age}</td>
        <td>{per.skill}</td>
      </tr>
    ));

    return (
      <div>
        <table>
          <thead>
            <tr>
              <td>Name</td>
              <td>Age</td>
              <td>skills</td>
            </tr>
          </thead>
          <tbody>{createRow}</tbody>
        </table>
        <button onClick={this.props.addtable}>CLICK</button>
      </div>
    );
  }
}

React.PureComponent's shouldComponentUpdate() skips prop updates for the whole component subtree. React.PureComponent 的 shouldComponentUpdate() 跳过整个组件子树的 prop 更新。 Make sure all the children components are also “pure”.确保所有子组件也是“纯”的。

Thats why your props not updating your components.这就是为什么你的道具没有更新你的组件。 Try it with React.Components用 React.Components 试试

You dont have to copy props into state in Child component.您不必将道具复制到子组件中的状态。

class CreateTablesam extends PureComponent {
  render() {
    const createRow = this.props.tabelDeatils.map(per => (
      <tr key={per.name}>
        <td>{per.name}</td>
        <td>{per.age}</td>
        <td>{per.skill}</td>
      </tr>
    ));

    return (
      <div>
        <table>
          <thead>
            <tr>
              <td>Name</td>
              <td>Age</td>
              <td>skills</td>
            </tr>
          </thead>
          <tbody>{createRow}</tbody>
        </table>
        <button onClick={this.props.addtable}>CLICK</button>
      </div>
    );
   }
  }

Also please make sure you are adding unique items in addtable function另外请确保您在 addtable 功能中添加了独特的项目

addRow() {
    let newdetails = {
      name: "ManiVEL"+ Math.random(),
      age: 25,
      skill: "REACT JS"
    };
    this.setState({
      userValues: [...this.state.userValues, newdetails]
    });
  }

Two problems两个问题

  1. Don't edit the existing array, rather create a new one.不要编辑现有数组,而是创建一个新数组。
  2. this.state = ... is run only once per instance of the component. this.state = ...每个组件实例只运行一次。 And since you're storing the tabelDeatils value there, it will never get updated.而且由于您将tabelDeatils值存储在那里,它永远不会更新。

The changes are as below变化如下

 const PureComponent = React.PureComponent; class Index extends PureComponent { constructor() { super(); this.state = { userValues: [ { name: "Mani", age: 23, skill: "Java" }, { name: "Vel", age: 23, skill: "react" } ] }; this.addRow = this.addRow.bind(this); } addRow() { let newdetails = { name: "ManiVEL", age: 25, skill: "REACT JS" }; this.setState({ userValues: [...this.state.userValues, newdetails] }); } render() { return ( <CreateTablesam addtable={this.addRow} tabelDeatils={this.state.userValues} ></CreateTablesam> ); } } class CreateTablesam extends PureComponent { render() { const createRow = this.props.tabelDeatils.map((per, idx) => ( <tr key={idx}> <td>{per.name}</td> <td>{per.age}</td> <td>{per.skill}</td> </tr> )); return ( <div> <table> <thead> <tr> <td>Name</td> <td>Age</td> <td>skills</td> </tr> </thead> <tbody>{createRow}</tbody> </table> <button onClick={this.props.addtable}>CLICK</button> </div> ); } } ReactDOM.render(<Index />, document.getElementById("root"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>

EDIT编辑

As mentioned in the comment, you need to add unique keys when generating elements in a loop.正如评论中提到的,在循环中生成元素时需要添加唯一键。 I've added the index in the array, but it's not advised to do so.我已经在数组中添加了索引,但不建议这样做。 You need to find something that is unique to each element and pass it as the key.您需要找到每个元素独有的东西并将其作为键传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM