React报Cannot assign to read only property错误如何解决
错误原因
[...props.resume.certifications] 属于浅拷贝,仅复制了数组本身的第一层结构,数组内存储的每个证书对象仍然保留对原状态中对象的引用。React 状态遵循不可变原则,状态内的嵌套对象默认是只读冻结状态,你直接执行 newCertificates[index][property] = value 本质上是在修改原状态里的只读对象,因此触发类型错误。
修复方法
方案1:手动做不可变更新(无额外依赖,推荐)
更新数组时,对需要修改的目标项单独做对象拷贝,所有修改都在新生成的对象上完成,不触碰原状态的只读值:
const handleInput = (index: number, property: string, value: any) => { const newCertificates = props.resume.certifications.map((cert, idx) => { // 命中要修改的索引时,返回拷贝后的新对象并覆盖目标属性 if (idx === index) { return { ...cert, [property]: value } } // 其他项直接返回原引用即可,不需要额外拷贝 return cert }) props.setResume({ ...props.resume, certifications: newCertificates }) }
额外建议:不要给参数全标
any,会丢失TypeScript的类型校验能力,可以先定义证书数据的接口,将index类型收窄为number,property收窄为证书对象的合法键名,提前规避传参错误。
方案2:使用Immer简化嵌套状态更新(适合复杂状态场景)
如果项目里存在大量嵌套状态更新的逻辑,可以引入Immer库,它会代理你的修改操作,自动生成符合不可变要求的新状态,不用手动写逐层拷贝逻辑:
import { produce } from 'immer' const handleInput = (index: number, property: string, value: any) => { props.setResume( produce(props.resume, (draft) => { // 直接写修改逻辑即可,immer会在底层处理不可变拷贝 draft.certifications[index][property] = value }) ) }
避坑提醒
不要用JSON.parse(JSON.stringify())做深拷贝来绕开只读问题,这种方式会丢失undefined、函数、Date实例、正则等特殊类型的值,很容易引发隐蔽的业务bug。
内容的提问来源于stack exchange,提问作者nevoni3008
相关产品推荐
相关产品推荐

