Ngrx : Cannot assign to read only property 'Property' of object '[Object]'
Solution 1
The basic principle of Redux pattern is immutability of state and its parts, because it let's us to detect changes just by object reference instead of comparing whole objects.
In your reducer, you cannot directly assign a property of state (state.actualTrips =
), because change detector (and selectors) would not detect it as changed.
To modify state, you return a copy of the state with new modifications.
const time = action.payload;
return {
...state,
actualTrips: [...(state.schedulings[time] || [])]
}
Solution 2
If you want to change state.actualTrips = myNewValue is not allowed because there is a strict Setting. So one way is may to clonedeep and return the object, like newState = cloneOfState... I didn't test it. So I changed the setting in app.module for Store. My Example: change the strictStateImmutability to false (full Docu here: https://ngrx.io/guide/store/configuration/runtime-checks )
StoreModule.forRoot(ROOT_REDUCERS_TOKEN, {
metaReducers,
runtimeChecks: {
// strictStateImmutability and strictActionImmutability are enabled by default
strictStateSerializability: true,
strictActionSerializability: true,
strictActionWithinNgZone: true,
strictActionTypeUniqueness: true,
// if you want to change complexe objects and that we have. We need to disable these settings
// change strictStateImmutability, strictActionImmutability
strictStateImmutability: false, // set this to false
strictActionImmutability: true,
},
}),
Solution 3
That error happened me when I changed the input values in the template. I was using Angular11 + NGRX11 so I understood I was changed a value from store, this was my fix:
Before:
this.store.dispatch(new Actions.LoginUser({ user: this.user }));
After:
const clone = {
user: Object.assign({}, this.user)
};
this.store.dispatch(new Actions.LoginUser(clone));
infodev
Updated on July 05, 2022Comments
-
infodev almost 2 years
I'm using ngrx store.
In my state I have to items
export interface ISchedulesState { schedulings: ISchedules; actualTrips: ISchedule[]; }
Here are my interfaces
export interface ISchedules { [key: string]: ISchedule[]; } export interface ISchedule { dest: number; data: string }
In reducer I update
actualTrips
export const SchedulingReducers = ( state = initialSchedulingState, action: SchedulesAction ): ISchedulesState => { switch (action.type) { case ESchedulesActions.GetSchedulesByDate: { return { ...state }; } case ESchedulesActions.GetSchedulesByDateSuccess: { return { ...state, schedulings: action.payload }; } case ESchedulesActions.GetSchedulesByTime: { let time = action.payload; state.actualTrips = [...(state.schedulings[time] || [])]; // if not data return empty array return state; } default: return state; } };
But actually I get an error
ERROR TypeError: Cannot assign to read only property 'actualTrips' of object '[object Object]'
-
CularBytes over 3 yearsBut the super annoying thing is that you want to modify for example a nested object (array in array in root object). As far as I can see, I have to do a deep-copy of the entire object tree and then update this in the store, which of course eats memory. How to avoid such a thing?
-
kvetis over 3 yearsWell the whole point of the redux pattern change detection is that you can check only the object references instead of deep comparing the objects. So in order for it to work you need to combine old references with the new references. If a deeply nested object is changed so is the tree above it and all the way to the root state. Then the change detection works. You can simplify the operation using a nested reducer.
-
Mansour Alnasser about 3 yearsI'm impressed that no one +1 your answer, thanks, worked for me.
-
Daniel M Sánchez over 2 yearsYou save my day, Thanks!!!
-
Ryan over 2 yearsYou may not want to disable strictStateImmutability checks. This is there for a reason. When using immutable state properly, you can enable OnPush Change Detection. This will radically improve performance. Also you may lose the ability to use Time-Travel debugging. Removing this check removes a lot of the benefits of NgRx. Check out the NgRx Example App for examples.
-
griest about 2 yearsThis didn't work for me in ngrx 13 in a testing environment.