React/NextJs push类对象到数组报object is not extensible错误
错误产生原因
报错TypeError: Cannot add property 0, object is not extensible的核心原因是你操作的usersList是不可扩展的只读对象:
- 你大概率是把
usersList定义为React的useState状态值,React会对state对象/数组做冻结处理,禁止直接修改原状态,直接调用push修改原数组就会触发这个错误 - 代码本身存在API误用:
Array.map是用来遍历返回新数组的方法,你用它做遍历执行push操作属于副作用场景的API错用,同时代码里先声明空对象再赋值为User实例的写法是冗余逻辑 - 额外维护的
isListMounted标记属于多余逻辑,不仅没必要,还容易引发闭包、重复执行之类的问题
可行修复方案
遵循React的不可变数据原则,不要直接修改原状态数组,先构造好全新的行数据数组,再通过state的setter方法完成更新,不需要手动执行push操作:
class User { constructor(id, name, email, measured, offset, paidAmount, status, home, misc, plane, transport, partner, isCoupon) { this.id = id this.name = name this.email = email this.measured = measured this.offset = offset this.paidAmount = paidAmount this.status = status this.home = home this.misc = misc this.plane = plane this.transport = transport this.partner = partner this.isCoupon = isCoupon } } // 用useState定义表格行状态,不要直接修改usersList const [usersList, setUsersList] = useState([]) useEffect(() => { if (rawData.length === 0) return // 直接通过map生成全新的User实例数组,全程不修改原状态 const tableRows = rawData.map(item => new User( item.ulid, item.Name, item.Email, item.Emissions, item.Quantity, item.Value, item.Status, item.Rawresult.home, item.Rawresult.misc, item.Rawresult.plane, item.Rawresult.transport, item.Partner, item.isCoupon )) // 传入新数组更新状态 setUsersList(tableRows) }, [rawData])
额外注意事项
- 如果
usersList是从Redux、React Query等第三方状态库获取的状态,这类库默认也会返回只读的冻结状态,同样不能直接push修改,必须走对应库的更新方法传入新数组 - 去掉原有代码里冗余的
isListMounted判断,useEffect本身会在rawData变化时执行,不会出现重复挂载列表的问题 - 不要在遍历map的回调里执行外部变量修改的副作用,需要遍历做副作用用
forEach,需要生成新数组直接用map返回结果即可
内容的提问来源于stack exchange,提问作者Kevin Marangoni
相关产品推荐
相关产品推荐

