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 />