Reactjs 删除项后,反应列表呈现错误数据

Reactjs 删除项后,反应列表呈现错误数据,reactjs,react-dom,Reactjs,React Dom,我有一个简单的学生对象列表,上面有名字和他们在州里的分数 他们的名字被绑定到{student.name},他们的分数被绑定到 <input type="text" defaultValue={student.score}/> 每当我想从列表中删除第一个学生时 通过调用set state重新呈现组件 第二个学生的输入标记,显示第一个学生的分数,而不是自己的分数。为什么我做错了呢 类应用程序扩展了React.Component{ 构造函数(){ 超级(); 这

我有一个简单的学生对象列表,上面有名字和他们在州里的分数

他们的名字被绑定到
{student.name}
,他们的分数被绑定到

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

每当我想从列表中删除第一个学生时 通过调用set state重新呈现组件

第二个学生的输入标记,显示第一个学生的分数,而不是自己的分数。为什么我做错了呢

类应用程序扩展了React.Component{
构造函数(){
超级();
这个州={
学生:[{姓名:“A”,分数:10},{姓名:“B”,分数:20},{姓名:“C”,分数:30}]
}
}
onDelete(索引){
this.state.students.splice(索引1);
this.setState(this.state);
}
render(){
返回(
{this.state.students.map((学生,索引)=>{
返回(
{student.name}-
删除
)
})}
)
}
}
render(,document.getElementById(“main”));

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

当修改数组时,删除索引后的学生将使用错误的键,React不会注册键更改以使用更新的数据重新渲染

你应该改为使用这样的东西

<div key={student.name}>


假设
student.name
是唯一的。

最好使用唯一id作为键,而不是索引。如果您的JSON没有提供唯一的Id,您可以使用uuid npm模块之类的东西为您生成它。这是链接

然后,您可以导入它并按如下方式使用

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

以前的状态
将被您的突变污染。因此,两种状态的浅层比较和合并将 不安或不会发生,因为你现在只有一个状态。 这将中断React的所有生命周期方法


你的问题与解决方案
  • 如果您使用的是输入
    只读
    ,则应将
    默认值
    更改为
    ,这样代码才能正常工作
  • 
    
    类应用程序扩展了React.Component{
    构造函数(){
    超级();
    此.state={
    学生:[
    {姓名:“A”,分数:10},
    {姓名:“B”,分数:20},
    {姓名:“C”,分数:30}
    ]
    };
    }
    onDelete(索引){
    const newStudents=[…this.state.students];
    新闻学生.剪接(索引1);
    this.setState({学生:新闻学生});
    }
    render(){
    返回(
    {this.state.students.map((学生,索引)=>{
    返回(
    {student.name}-{”“}
    删除
    );
    })}
    );
    }
    }
    ReactDOM.render(,document.getElementById('app'))
    
    
    
    非常感谢。但为什么它与输入类型=“text”以外的任何其他标记一起工作?
    input
    (即
    span
    )或其他输入类型以外的任何其他标记一起工作?
    defaultValue
    在更改时不会更新。。。您需要丢弃该元素并重新生成它(即更改
    )。。而另一个元素可能可以正常工作。如果您使用了
    value
    ,它可能会起作用。。但是,除非您给它一个
    onChange
    处理程序,否则您将只有一个只读输入。我为初始化的对象生成了随机的6位数字作为ID,在迭代时将这些数字设置为键,这解决了我的问题。在api未提供时生成唯一ID是一个好主意,但您应该在渲染之前这样做。如果你在渲染过程中像你在回答中所建议的那样这样做,你基本上是不断地一次又一次地重新创建id,因此每次有更新,你都会得到一个新id。这会导致不必要的渲染,如果你有一个输入字段,它将失去对每个字符输入的关注。我的意思是生成id,谢谢你的捕获。编辑了我的答案。不好的主意,如果你一直给子组件状态分配新的键,你会破坏它。在每个渲染上生成一个新的键不仅会导致性能问题,还会引入错误。我根本不建议将其作为解决方案。
    onDelete(index) {
        const newStudents = [...this.state.students];
        newStudents.splice(index, 1);
        this.setState({ students: newStudents });
    }
    
    <input type="text" value={student.score} readOnly />