我有一个简单的学生对象列表,其名称和状态分数。
他们的名字绑定到<b>{student.name}</b>
,他们的分数必然会
<input type="text" defaultValue={student.score}/>
什么时候我想从这个列表中删除第一个学生 通过调用set state
重新呈现组件第二个学生的输入标签显示第一个学生的分数而不是拥有自己的分数。为什么这会发生在我做错的地方?
这是我的代码here is mycode in 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"));
答案 0 :(得分:12)
这是因为您使用key={index}
而不是学生唯一的值。
当数组被修改后,删除索引后的学生将使用错误的密钥,并且React不会注册密钥更改以使用更新的数据重新呈现。
你应该改用这样的东西......
<div key={student.name}>
假设student.name
是唯一的。
答案 1 :(得分:2)
使用唯一ID作为键而不是索引总是更好。如果您的JSON没有提供唯一的ID,您可以使用类似uuid npm模块的东西来为您生成它。这是链接https://www.npmjs.com/package/uuid。
然后您可以导入它并使用如下
import { v4 } from 'uuid'; //there are 5 versions. You can use any.
然后通过调用v4函数(如下面的
)使用它来生成uique Idid={v4()}
答案 2 :(得分:0)
老实说,你不应该直接改变状态数据。你应该克隆然后像这样完成你的任务
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
Why can't I directly modify a component's state, really?
<块引用>previous state
将被您的突变污染。因此,两个状态的浅比较和合并将是
不安或不会发生,因为你现在只有一种状态。
这将破坏 React 的所有生命周期方法。
readOnly
,您应该将 defaultValue
更改为 value
,然后您的代码运行良好。<input type="text" value={student.score} readOnly />
class App extends React.Component {
constructor() {
super();
this.state = {
students: [
{ name: "A", score: 10 },
{ name: "B", score: 20 },
{ name: "C", score: 30 }
]
};
}
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
render() {
return (
<div>
{this.state.students.map((student, index) => {
return (
<div key={index}>
<b>{student.name}</b> -{" "}
<input type="text" value={student.score} readOnly />
<button onClick={this.onDelete.bind(this, index)}>delete</button>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
key
。如果 student.name
不是唯一的,您可以像这样随机 GUID
。const getGUID = () => "id" + Math.random().toString(16).slice(2);
> <div key={getGUID()}>
const getGUID = () => "id" + Math.random().toString(16).slice(2);
class App extends React.Component {
constructor() {
super();
this.state = {
students: [
{ name: "A", score: 10 },
{ name: "B", score: 20 },
{ name: "C", score: 30 }
]
};
}
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
render() {
return (
<div>
{this.state.students.map((student, index) => {
return (
<div key={getGUID()}>
<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('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
但是,在这种情况下,Unstable 键将 cause harmful performance,因为组件实例 - Virtual DOM
和 DOM 节点 - actual DOM
将总是不必要的重新创建。
简而言之,根据您的数据和行为,您可以选择正确的方式来完成它。