React使用useState给嵌套对象赋值时报Cannot set properties of undefined错误
报错原因
该报错是两个问题共同导致的:
- 初始
errors状态为空对象{},本身不存在email属性,所以errors.email的取值为undefined,直接尝试给undefined设置primary属性自然会抛出对应错误。 - 你的写法直接修改了state原对象,不符合React状态不可变的更新规范,哪怕不报错也可能导致视图无法正常触发更新。
正确实现方案
方案1:原生React手动展开实现(无需额外依赖)
调用setErrors时传入新的状态对象,逐层展开原有属性避免覆盖已有的值,同时补全嵌套的上层结构:
import "./styles.css"; import { useState, useEffect } from "react"; export default function App() { const [errors, setErrors] = useState({}); useEffect(() => { // 使用函数式更新获取最新的prevErrors状态,避免闭包问题 setErrors(prevErrors => ({ ...prevErrors, // 保留errors下除email外的其他已有属性 email: { ...prevErrors.email, // 保留email下除primary外的其他已有属性 primary: "abc@gmail.com" } })) }, []); return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> </div> ); }
方案2:使用immer库简化深层嵌套更新(适合复杂嵌套场景)
如果嵌套层级很深,手动逐层展开很容易出错,可以使用immer库来实现类似直接修改原对象的写法,内部自动生成不可变的新状态:
- 先安装依赖:
npm install immer use-immer - 替换原有useState为useImmer:
import "./styles.css"; import { useEffect } from "react"; import { useImmer } from "use-immer"; export default function App() { const [errors, setErrors] = useImmer({}); useEffect(() => { setErrors(draft => { // 这里可以直接修改draft对象,immer会自动生成新的不可变状态 if (!draft.email) draft.email = {}; // 补全上层结构 draft.email.primary = "abc@gmail.com"; }) }, []); return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> </div> ); }
内容的提问来源于stack exchange,提问作者CCCC
相关产品推荐
相关产品推荐

