You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:15:32