React Hooks:如何使用useState更新包含数组的嵌套对象状态
问题根因
你遇到的只读报错来自三个核心问题:
- 从Redux/RTK接口返回的原始数据默认是不可变(immutable)结构,直接修改原始对象的嵌套属性会被底层限制拦截
- 参数调用和使用顺序不匹配:调用
updateAnswerTexts时传入的参数顺序是(event, prop, 选项key, i18n下标),但之前的实现里把下标和选项key的使用顺序搞反了 - 仅做了顶层对象的浅拷贝,嵌套层级的对象/数组仍然引用原始的只读对象,修改时自然触发只读限制
正确实现方案
方案1:手动逐层做不可变更新
不需要引入额外依赖,每层嵌套结构都生成新的引用替换:
const updateAnswerTexts = (event, prop, optionKey, i18nIndex) => { const newVal = event.target.value; setAnswerData(prevState => { // 拷贝顶层状态对象 const newState = {...prevState}; // 拷贝当前要修改的答案选项对象 const targetOption = {...newState[optionKey]}; // 拷贝选项下的多语言文本数组 const newI18nList = [...targetOption.textI18Ns]; // 拷贝要修改的单条多语文本,更新目标字段 const updatedI18nItem = {...newI18nList[i18nIndex], [prop]: newVal}; // 逐层替换回新状态 newI18nList[i18nIndex] = updatedI18nItem; targetOption.textI18Ns = newI18nList; newState[optionKey] = targetOption; return newState; }) }
方案2:用Immer简化嵌套更新
如果项目嵌套结构多,可以引入Immer库做不可变更新,不需要手动逐层拷贝:
- 先安装依赖:
npm install immer
- 修改更新逻辑:
import { produce } from 'immer'; const updateAnswerTexts = (event, prop, optionKey, i18nIndex) => { const newVal = event.target.value; setAnswerData(prev => produce(prev, draft => { // 直接修改draft对象即可,Immer内部会处理不可变更新 draft[optionKey].textI18Ns[i18nIndex][prop] = newVal; }) ) }
内容的提问来源于stack exchange,提问作者iwonttellyou whoiam
相关产品推荐
相关产品推荐

