如何正确更新React中的嵌套State以切换按钮选中状态?
嵌套React State的正确更新方式
你的代码存在几个核心问题,导致状态无法正确更新、子组件无法同步刷新,以下是问题分析和正确实现方案:
错误点分析
- 直接修改State对象的属性(
pref.selected = ...):React依赖State的引用变化触发重渲染,直接修改原对象不会生成新引用,React无法感知状态变更。 - 硬编码id判断:只处理了
intro中的两个id,完全没覆盖experience的元素,逻辑扩展性极差。 - 传递原对象给
setButtonObject:没有创建新的对象/数组副本,React会认为State没有变化,跳过重渲染。
正确实现代码
const handleButtonClick = ({ id }) => { setButtonObject(prevState => { // 遍历state中的所有分组(intro、experience) return Object.fromEntries( Object.entries(prevState).map(([groupKey, groupItems]) => { // 对当前分组的数组进行不可变更新 const updatedItems = groupItems.map(item => { // 找到目标id的元素,切换selected状态 if (item.id === id) { return { ...item, selected: !item.selected }; } // 其他元素直接返回原对象 return item; }); return [groupKey, updatedItems]; }) ); }); };
关键要点
- 使用函数式更新:通过
prevState获取最新的State值,避免闭包导致的旧值问题。 - 不可变更新:
- 对每个分组数组使用
map生成新数组,不修改原数组。 - 对需要修改的元素,用扩展运算符
{ ...item }创建新对象,仅修改selected属性,保留其他属性不变。 - 用
Object.entries和Object.fromEntries处理顶层分组对象,生成新的顶层对象,确保引用变化。
- 对每个分组数组使用
- 通用逻辑:无需硬编码id或分组名称,自动处理所有分组中的元素,扩展性强。
简化版(针对固定分组)
如果你的分组固定只有intro和experience,可以写更直观的版本:
const handleButtonClick = ({ id }) => { setButtonObject(prevState => ({ ...prevState, intro: prevState.intro.map(item => item.id === id ? { ...item, selected: !item.selected } : item ), experience: prevState.experience.map(item => item.id === id ? { ...item, selected: !item.selected } : item ) })); };
内容的提问来源于stack exchange,提问作者Taylor Dorsett
相关产品推荐
相关产品推荐

