将useState数据存入Redux Toolkit后setState报错:无法赋值只读属性
问题原因与解决方案
核心问题
Redux Toolkit 默认会冻结存储在 store 中的状态对象(防止直接修改违反不可变原则)。当你把组件的 listData 直接 dispatch 到 Redux 后,组件内的 listData 和 Redux store 里的对象是同一个引用,这个对象会被 Redux 标记为只读。后续调用 changeName 时直接修改该对象的属性,就会触发 Cannot assign to read only property 错误。
具体解决方案
1. 切断组件 state 与 Redux state 的引用
在提交到 Redux 时,先对 listData 做深拷贝,避免原对象被 Redux 冻结后影响组件内的修改:
const submit = ()=>{ // 深拷贝原数据,切断引用 const copiedData = JSON.parse(JSON.stringify(listData)); dispatch(changeNameArr(copiedData)); }
2. 修正组件内的状态修改逻辑
确保每次修改组件 state 时,都是基于原状态的深拷贝进行修改,不直接触碰原对象:
const changeName = () =>{ setListData(prevState => { // 深拷贝原状态,生成可修改的新对象 const newState = JSON.parse(JSON.stringify(prevState)); if (notepadList[1] === undefined) { newState.orderItem[notepadList[0]].price = value; } else { newState.orderItem[notepadList[0]].orderItemsOptions[notepadList[1]].price = value; } return newState; }); }
3. 规范 Redux Reducer 写法(基于 Redux Toolkit 的 Immer)
Redux Toolkit 内置 Immer,支持直接修改 draft state,不需要手动展开对象,以下是正确的 reducer 写法(根据你的业务需求选择):
// 假设使用 createSlice 创建 slice const yourSlice = createSlice({ name: 'yourSlice', initialState: { list: [] // 初始状态根据业务调整 }, reducers: { // 如果是向 list 数组添加新数据 changeNameArr: (state, action) => { state.list.push(action.payload); }, // 如果是替换整个 list 对象 // changeNameArr: (state, action) => { // state.list = action.payload; // } } });
验证逻辑
- 页面初始化时,组件 state 是独立的可修改对象,
changeName正常工作。 - 提交到 Redux 时,传递的是拷贝后的对象,原组件 state 不会被冻结。
- 后续调用
changeName时,始终基于深拷贝的新对象修改,不会触碰只读属性。
内容的提问来源于stack exchange,提问作者user19539777
相关产品推荐
相关产品推荐

