React中每次状态变更时如何检测对象变化并收集变更ID
功能需求
对比新旧两组对象数组,检测其中的变更项,将发生变更的对象ID存入状态中。
原代码问题排查
原代码存在几处会直接导致功能失效的错误:
- 命名拼写不一致:定义的状态为
idOfChangedItem、skillsSets,代码中错误使用idOfChangedItems、skillsSet,会直接触发引用报错 - 初始值类型错误:
skillsSets后续要调用数组方法.map(),初始化时却用对象展开语法把数组转成了对象,调用map时会直接抛错 - 对比逻辑错误:遍历新数组时,直接拿单个新项和整个旧数组对象
oldSkillObject做对比,没有按ID匹配对应的旧项,对比结果完全无效 - 状态更新缺失:收集到变更ID后没有调用
setIdOfChangedItem触发状态更新,变更列表永远为空 - 存在闭包陷阱:即使补充了状态更新逻辑,循环中每次都拿初始状态的
idOfChangedItem做展开,会导致之前收集的变更ID被覆盖
修正后实现代码
// allSkills如果是数组类型,直接传入初始化即可,不需要转成对象 const [skillsSets, setSkillSets] = useState(allSkills) const [idOfChangedItem, setIdOfChangedItem] = useState([]) useEffect(() => { // 先将旧数据转为ID映射表,提升对比时的查找效率 const oldSkillMap = new Map(oldSkillObject.map(item => [item.id, item])) // 一次性过滤出所有变更项的ID,避免循环中重复操作状态 const changedIds = skillsSets .filter(skillSet => { const matchedOldItem = oldSkillMap.get(skillSet.id) // 不存在匹配旧项判定为新增(属于变更),存在匹配项则走自定义对比逻辑 return !matchedOldItem || checkForChange(skillSet, matchedOldItem) }) .map(skillSet => skillSet.id) // 批量更新变更ID状态 setIdOfChangedItem(changedIds) // 依赖项需与使用的状态名完全一致,避免拼写错误 }, [skillsSets])
优化建议
- 如果
checkForChange还未实现,浅对比场景可以直接遍历对象第一层属性做值对比,深对比场景建议按ID匹配后单对单对比,不要直接做两个全量大数组的深递归,避免性能损耗 - 如果不需要每次
skillsSets变化都全量重算所有变更ID,可以在更新skillsSets的逻辑里直接对比新旧值,增量更新变更ID列表,性能更优 - 状态命名保持单复数统一,避免后续维护时出现低级拼写错误
内容的提问来源于stack exchange,提问作者bohokep350
相关产品推荐
相关产品推荐

