React加购后修改商品规格state报只读属性value赋值错误
报错产生原因
这个错误是状态浅拷贝导致跨模块引用共享+对象被冻结引发的,触发链路非常明确:
- 你在
handleAddToCart方法中,直接将组件state中selected_variation数组存储的对象引用,赋值给了order数组,最终通过props.addToCart(data)传入了全局购物车状态。 - 绝大多数React生态的状态管理方案(Redux严格模式、Immer、Zustand不可变模式等)都会对存入全局状态的对象执行
Object.freeze()冻结操作,让对象变为只读,避免意外的直接状态修改。 - 由于你没有切断引用,组件本地state里
selected_variation存的对象,和购物车全局状态里存的是同一个内存地址的对象,加购完成后这些对象就变成了只读属性。 - 你在
handleVariation里写的const newData = [...this.state.selected_variation]仅做了数组的浅拷贝,数组内存储的对象还是原引用;后续执行newData[index].value = value时,本质是在直接修改已经被冻结的只读对象,直接触发类型错误。
这也是为什么报错只在加购完成后才出现:加购前这些对象是组件本地的普通可变对象,直接修改不会触发报错;加购后对象被全局状态冻结,再修改就会抛出只读错误。
对应报错截图:
对应规格选择交互位置:
可落地修复方案
核心要遵守React状态不可变原则,彻底切断跨状态的引用共享,不要直接修改原对象:
1. 修复handleVariation的状态更新逻辑
替换原有浅拷贝+直接改属性的写法,更新状态时对要修改的项生成全新对象,避免操作原引用:
const handleVariation = (e) =>{ const type = e.target.name; const value = e.target.value; // 查找已选规格的索引 const index = this.state.selected_variation.findIndex((x)=> x.type === type) // 不存在则新增 if(index === -1){ this.setState({ selected_variation: [...this.state.selected_variation, {type,value}] }) }else{ // 通过map遍历生成新数组,对要修改的项返回新对象,彻底切断引用 const newData = this.state.selected_variation.map((item, idx) => { if(idx === index) { // 返回全新对象,不修改原item return { ...item, value } } return item }) this.setState({ selected_variation: newData, }) } }
2. 修复handleAddToCart的传值逻辑
传入购物车的规格数据做一次拷贝,不要直接把组件state的原引用传到全局状态,从源头避免引用共享:
const handleAddToCart = () => { // 生成排序后的规格列表时,对匹配到的规格项做拷贝,不直接传state原对象 const order = product.attributes.map((attribute) => { const matched = this.state.selected_variation.find((v) => v.type === attribute.id) return matched ? { ...matched } : null }).filter(Boolean); if (order.length === product.attributes.length) { const data = { variation: order, product: product, quantity: this.state.quantity, id:`${product.id}+${order.map((item) => `${item.type}=${item.value}`).join("+")}` }; this.props.addToCart(data); } else { alert("请选择所有规格,或所选规格商品已在购物车中"); } };
关键注意点
- 数组展开
[...]、对象展开{...obj}都属于浅拷贝,只会拷贝第一层结构,嵌套的对象/数组依然是共享引用 - 任何时候更新React状态,都不要直接修改原state上的属性,要生成新的引用替换,避免出现难以追踪的状态污染问题
内容的提问来源于stack exchange,提问作者sarangkkl
相关产品推荐
相关产品推荐

