我有一个简单的学生对象列表,其中包含名称和他们在州中的分数。
他们的名字绑定到<b>{student.name}</b>
,他们的分数绑定到
<input type="text" defaultValue={student.score}/>
每当我想从这个列表中删除第一个学生并通过调用set state重新呈现组件时。
第二个学生的输入标签显示了第一个学生的分数,而不是有自己的。为什么在我做错的地方会发生这种情况?
Here is my code 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"));
4条答案
按热度按时间wko9yo5t1#
这是因为您使用的是
key={index}
,而不是学生特有的值。当数组被修改时,删除索引后的学生将具有错误的键,React将不会注册键更改以使用更新的数据重新渲染。
你应该用这样的东西...
假设
student.name
是唯一的。uplii1fm2#
最好使用unique id作为键,而不是索引。如果你的JSON没有提供unique Id,你可以使用uuid npm模块来生成它。这是链接https://www.npmjs.com/package/uuid。
然后,您可以将其导入并按如下方式使用
然后使用它通过调用v4函数生成uique Id,如下所示
0ve6wy6x3#
最佳实践
老实说,你不应该直接改变状态数据,你应该克隆然后像这样完成你的任务
Why can't I directly modify a component's state, really?
previous state
将被你的突变污染。因此,两个状态的浅层比较和合并将被干扰或不会发生,因为你现在只有一个状态。这将干扰所有React的生命周期方法。您的问题和解决方案
1.如果您使用输入
readOnly
,您应该从defaultValue
更改为value
,然后您的代码工作良好。一个二个一个一个
1.否则,您应该提供唯一的
key
,如果student.name
不唯一,您可以像这样随机GUID
。然而,在这种情况下,不稳定的键将导致有害的性能,因为组件示例-
Virtual DOM
和DOM节点-actual DOM
将总是不必要的重新创建。总之,取决于你的数据和行为,你可以选择正确的方式来完成它。
46scxncf4#
'''const getGUID =()=〉“id”+数学.随机().到字符串(16).切片(2);
'''
工作起来很有魅力!