JavaScript可变数组报错:TypeError: Attempted to assign to readonly property
问题分析与解决方案
错误根源
你遇到的TypeError: Attempted to assign to readonly property是因为Redux Saga中错误地将全局数组直接作为action传递,导致该数组被Redux标记为只读(Redux要求状态不可变,会对传入的状态对象/数组进行冻结处理),后续执行notes.push()时无法修改只读数组,触发报错。
关键问题出在Saga代码的yield put(all());——put方法仅用于分发标准Redux action对象,而非直接传递数组。这里的all()返回全局notes数组,直接传入put会导致Redux将该数组转为只读状态。
具体修复方案
1. 修正Redux Saga的action分发逻辑
将直接传递数组改为分发标准action,让Redux reducer负责状态更新:
function* workerSaveNote(action: any) { try { yield NoteService.save(action.payload); // 获取最新的笔记列表 const latestNotes = yield NoteService.all(); // 分发标准action更新Redux状态 yield put({ type: 'SET_NOTES', payload: latestNotes }); } catch(e) { console.error(e); } }
2. 移除全局数组,改用Redux管理状态(推荐)
全局数组与Redux混合使用容易引发状态不一致问题,建议将notes完全交给Redux维护:
- 添加Reducer:
const initialState = { notes: [] }; function notesReducer(state = initialState, action) { switch (action.type) { case 'SET_NOTES': return { ...state, notes: action.payload }; default: return state; } }
- 业务代码中通过Selector获取状态:
// React项目示例(使用useSelector) // const notes = useSelector(state => state.notes.notes);
3. 若必须保留全局数组,避免被Redux冻结
如果坚持使用全局数组,需确保它不会被Redux处理为只读:
- 移除Saga中的
put(all()),改为重新初始化数组:
function* workerSaveNote(action: any) { try { yield NoteService.save(action.payload); // 重新初始化数组,断开与可能被冻结的原数组的引用 yield NoteService.initialize(); } catch(e) { console.error(e); } }
- 同时修改
initialize方法,创建新数组避免引用冻结对象:
const initialize = async() : Promise<Note[]> => { // 解构创建新数组,脱离原冻结数组的引用 notes = [...(await NoteStore.all())]; return notes; }
内容的提问来源于stack exchange,提问作者Aftab Naveed
相关产品推荐
相关产品推荐

