React修改嵌套对象数组状态时出现Cannot read properties of undefined错误
问题描述
尝试修改名为configure的嵌套数组状态时,触发错误:Cannot read properties of undefined (reading 'map')。场景是通过以下代码向指定分区的字段数组添加元素:
const [tabValue, setTabValue] = useState(0); const [configure, setConfigure] = useState(config); const addField = (name: string, value: any, type: string) => { const newItem = { _id: uuidv4(), name, value, type } const newArr = [...configure.sections[tabValue].fields, newItem] setConfigure((prevState: any) => ({ ...prevState.sections[tabValue], fields: newArr })); console.log(configure) }
其中tabValue代表当前操作的分区索引。渲染时的以下代码触发了上述错误:
return ( <div className="App"> <SearchForm handleUpdateSearch={handleUpdateSearch} /> <CreateForm onAdd={addField} /> <TabList tabValue={tabValue} setTabValue={setTabValue} configure={configure} setConfigure={setConfigure} /> {configure.sections.map((s: any, i: any) => { return ( <> {tabValue === i && <Section {...s} configure={configure} setConfigure={setConfigure} tabValue={tabValue} />} </> ) })} </div> );
已知configure是包含sections数组的对象,每个section项包含fields数组(嵌套结构)。
问题分析
你判断的没错,问题出在状态更新时的对象展开逻辑错误:
- 原代码中
setConfigure的回调只返回了prevState.sections[tabValue]的展开结果+修改后的fields,这相当于把整个configure状态替换成了单个section对象,而非完整的原结构。 - 新状态里不再有
sections属性,所以渲染时configure.sections会变成undefined,调用map时就触发了报错。
解决方案
需要完整保留configure的原有结构,只修改目标分区的fields数组,正确的状态更新逻辑如下:
方案一:分步复制修改
const addField = (name: string, value: any, type: string) => { const newItem = { _id: uuidv4(), name, value, type }; setConfigure((prevState: any) => { // 1. 复制原sections数组,避免直接修改原状态 const updatedSections = [...prevState.sections]; // 2. 复制目标分区对象,修改其fields数组 const updatedSection = { ...updatedSections[tabValue], fields: [...updatedSections[tabValue].fields, newItem] }; // 3. 替换sections数组中的目标分区 updatedSections[tabValue] = updatedSection; // 4. 返回完整的configure新状态 return { ...prevState, sections: updatedSections }; }); };
方案二:用数组map简化写法
const addField = (name: string, value: any, type: string) => { const newItem = { _id: uuidv4(), name, value, type }; setConfigure((prevState: any) => ({ ...prevState, sections: prevState.sections.map((section: any, index: number) => { if (index === tabValue) { return { ...section, fields: [...section.fields, newItem] }; } return section; }) })); };
另外注意:console.log(configure)无法看到更新后的状态(因为setState是异步的),如果要验证更新结果,可以在setConfigure的回调里打印,或者用useEffect监听configure的变化。
内容的提问来源于stack exchange,提问作者Богдан Шевченко
相关产品推荐
相关产品推荐

