删除项目后react列表呈现错误数据

IT技术 reactjs react-dom
2021-05-14 06:01:39

我有一个简单的学生对象列表,其中包含名称和状态分数。

他们的名字是必然的<b>{student.name}</b>,他们的分数是必然的

<input type="text" defaultValue={student.score}/>

每当我想从这个列表中删除第一个学生并通过调用 set state 重新渲染组件时。

第二个学生的输入标签显示第一个学生的分数,而不是自己的。为什么会在我做错的地方发生这种情况??

这是我的代码jsbin

class App extends React.Component{
  constructor(){
    super();
    this.state ={
      students:[{name:"A",score:10},{name:"B",score:20},{name:"C",score:30}]
    }
  }
  
  onDelete(index){
    this.state.students.splice(index,1);
    this.setState(this.state);
  }
  
   render(){
     return(
       <div>
         {this.state.students.map((student,index)=>{
              return(
                <div key={index}>
                    <b>{student.name}</b> - <input type="text" defaultValue={student.score}/>
                     <button onClick={this.onDelete.bind(this,index)}>delete</button>
                </div>                
              )
         })}
       </div>
     )
   }
}


ReactDOM.render(<App/>,document.getElementById("main"));
3个回答

这是因为您正在使用key={index}而不是学生独有的值。

当数组被修改时,删除索引后的学生将拥有错误的键,并且 React 不会注册键更改以使用更新后的数据重新呈现。

你应该使用这样的东西......

<div key={student.name}>

假设这student.name是唯一的。

使用唯一 id 作为键而不是索引总是更好。如果您的 JSON 没有提供唯一的 Id,您可以使用类似 uuid npm 的module来为您生成它。这是链接https://www.npmjs.com/package/uuid

然后您可以导入它并使用如下

import { v4 } from 'uuid'; //there are 5 versions. You can use any.

然后使用它通过调用 v4 函数来生成 uique Id,如下所示

id={v4()}

最佳实践

老实说,你不应该直接改变状态数据。你应该克隆然后像这样完成你的任务

onDelete(index) {
    const newStudents = [...this.state.students];
    newStudents.splice(index, 1);
    this.setState({ students: newStudents });
}

为什么我不能直接修改组件的状态,真的吗?

previous state会与你的基因突变被污染。因此,两个状态的浅比较和合并将受到干扰或不会发生,因为您现在只有一个状态。这将破坏 React 的所有生命周期方法。


您的问题和解决方案

  1. 如果您使用 input readOnly,您应该从 更改defaultValuevalue 然后您的代码运行良好。
<input type="text" value={student.score} readOnly />

  1. 否则,您应该提供唯一的key. 如果student.name不是唯一的,你可以随意GUID这样。
const getGUID = () => "id" + Math.random().toString(16).slice(2);
>  <div key={getGUID()}>

然而,在这种情况下,不稳定的键会导致有害的性能,因为组件实例 -Virtual DOM和 DOM 节点 -actual DOM将总是不必要的重新创建。

总之,取决于你的数据和行为,你可以选择正确的方式来完成它。