React待办列表删除任务时控制台日志显示错误问题排查
问题原因与解决方案
错误核心原因
使用数组索引作为<ToDo>组件的key,这是React列表渲染的典型错误。
React通过key识别列表组件的唯一性,当用索引作为key时,一旦列表元素发生删除/顺序调整,React会错误复用组件,导致卸载逻辑触发异常:
- 初始状态下,三个任务对应的组件
key为0(upload slides)、1(grade lab activities)、2(lecture recording) - 删除第一个任务后,新列表的组件
key变为0(grade lab activities)、1(lecture recording) - React判定
key=2的组件不再存在,因此卸载原key=2对应的组件(即原第三个任务的<ToDo>),而非实际被删除的第一个任务组件 - 最终
componentWillUnmount打印的是被卸载组件的item.name,也就是原第三个任务的名称,和实际删除的任务不符
解决方案
1. 给任务项添加唯一标识,替换索引作为key
React要求列表组件的key必须稳定且唯一,不能随列表变化而改变。我们给每个任务添加id属性:
修改初始state:
this.state = { items: [ {id: 1, name: "upload slides", selected: false}, {id: 2, name: "grade lab activities", selected: false}, {id: 3, name: "lecture recording", selected: false} ], itemToBeAdded: "" };
修改添加任务的逻辑,生成唯一id:
addItem(e) { if(this.state.itemToBeAdded === "") { return; } // 用时间戳生成临时唯一id,生产环境可使用uuid库 const newItem = { id: Date.now(), name: this.state.itemToBeAdded, selected: false }; this.setState({items: [...this.state.items, newItem]}); }
修改列表渲染的key:
{ this.state.items.map((item) => ( <ToDo key={item.id} dataKey={item.id} item={item} selectItem={this.selectItem}/> )) }
2. 调整selectItem函数,适配id作为标识
原来的selectItem用索引定位元素,现在改为通过id查找:
selectItem(itemId) { this.setState(prevState => { const items = prevState.items.map(item => { if(item.id === itemId) { return {...item, selected: !item.selected}; } return item; }); return { items }; }); }
为什么之前的修改无效
你之前对removeItem和selectItem的修改,只是优化了state更新的不可变性,解决了状态修改的潜在问题,但没有触及key使用索引的根本矛盾,因此控制台的错误打印问题依然存在。
内容的提问来源于stack exchange,提问作者zee00001
相关产品推荐
相关产品推荐

