React Checklist排序后点击选中状态异常问题求助
问题排查与解决方案:勾选Checklist条目后索引混乱导致错误触发状态变更
嘿,我来帮你搞定这个头疼的问题!你遇到的点击后触发错误条目状态的问题,核心原因是你把排序/过滤后临时数组的索引,当成了原数据数组的真实索引来用,咱们来仔细拆解:
问题根源
- 你在
render里对原始的items数组做了filter+sort操作,这会生成一个全新的临时数组,这个数组里元素的顺序和原allChecklists中的items数组已经完全不一样了; - 你把临时数组
map时的循环索引i传给了ChecklistItem作为indexOfItem,但当调用check方法时,你用这个i去访问原数组的元素——这就完全错位了!比如原索引0的条目被排序到了临时数组的索引1,你点击它时,代码会去修改原数组索引1的条目,而不是你实际点击的那个。
解决方案(两种可选)
方案1:用唯一标识代替索引(推荐)
既然每个条目都有唯一的itemName,咱们直接用这个标识来定位要修改的元素,彻底摆脱索引依赖:
首先修改check方法,通过itemName找到原数组中的对应索引:
check = itemName => { const targetChecklist = this.state.allChecklists[this.state.selectedChecklist]; // 找到对应item在原数组中的真实索引 const targetIndex = targetChecklist.items.findIndex(item => item.itemName === itemName); const isChecked = targetChecklist.items[targetIndex].checked; this.setState({ allChecklists: update(this.state.allChecklists, { [this.state.selectedChecklist]: { items: { [targetIndex]: { checked: { $set: !isChecked } } } } }) }); };
然后修改Checklists2的render中map的部分,传递itemName而非临时索引:
.map((item) => { return ( <ChecklistItem key={item.itemName} itemName={item.itemName} checklistItem={item} toggleCheck={this.check} toggleCollapse={this.collapse} /> ); })
最后修改ChecklistItem的点击事件,传入itemName:
<button onClick={() => this.props.toggleCheck(this.props.itemName)}>Click me</button>
方案2:保留原数组索引
如果你更习惯用索引操作,可以在过滤排序前给每个元素带上原数组的索引:
修改Checklists2的render中的数组处理逻辑:
{this.state.allChecklists[this.state.selectedChecklist].items // 先给每个元素加上原数组的索引 .map((item, originalIndex) => ({ ...item, originalIndex })) .filter(item => { if (item.itemName.includes(this.state.searchTerm)) return true; return false; }) .sort((item, item2) => { if(item.checked) return 1 else return 0 }) .map((item) => { return ( <ChecklistItem key={item.itemName} indexOfItem={item.originalIndex} // 传递原索引 checklistItem={item} toggleCheck={this.check} toggleCollapse={this.collapse} /> ); })}
这样check方法不需要任何修改,因为传递的是原数组的真实索引,不管临时数组怎么排序,都能精准定位到要修改的元素。
额外小建议
- 尽量避免依赖数组索引来操作状态数据,尤其是当数组会被排序、过滤、增删时,索引很容易失效,唯一标识(比如
itemName、ID)是更可靠的选择; componentWillMount已经被React官方废弃了,建议换成componentDidMount,或者直接在constructor里初始化状态,当然如果能改成函数组件+Hooks会更符合React的现代写法~
内容的提问来源于stack exchange,提问作者Louis
相关产品推荐
相关产品推荐

