I am finding that props that I send into actions (ex: a class model with search criteria to send to the API) are becoming immutable and I can not modify the properties of that class.
Now, I understand that reducer / store objects are immutable, but this class is never touching a reducer or getting into the store at any point.
I have been working with Ngrx for a couple of years now and I just came across some behavior that I either didn't realize was there or is new. Perhaps I am missing something entirely somewhere else, but any insight is appreciated...
Take this simple action that takes in a class prop to represent a request:
export const loadNotes= createAction('[Notes] Load Notes',
props<{ getNotesRequestModel: GetNotesRequestModel }>()
);
An effect then fires for this action to call a service that loads the notes:
loadNote$ = createEffect(() =>
this.actions$.pipe(
ofType(NoteActions.loadNotes),
switchMap((action) =>
from(
this.noteService.getNotesList(action.getNotesRequestModel)
).pipe(
map((response) => {
return NoteActions.loadNotesSuccess({ response });
}),
catchError((error) => {
return of(NoteActions.loadNoteFail());
})
)
)
)
);
Finally, a reducer handles storing the response in state:
on(NoteActions.loadNotesSuccess,(state: INoteState, { response }) => ({
...state,
noteResponse: response,
})),
This all works fine, except that the after the action is first called, the local getNotesRequestModel variable is now immutable, which prevents me from changes to the properties like pageing, etc. to make followup calls to the API.
However, if I modify the dispatch to clone the request object, it works fine.
public getNotes(){
this.noteStore.dispatch(
NotesActions.loadNotes({getNotesRequestModel: _.cloneDeep(this.noteRequest)})
);
}
Update:
Research of the Ngrx version history shows that from version 8.6 to 9, strict action immutability was set to true by default. I had forgotten this and why I had not experienced the behavior before.
If desired, strict immutability can be controlled through the StoreModule setup as follows:
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
StoreModule.forRoot(reducers, {
metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
}
}),
.....
],
providers: [],
bootstrap: [AppComponent]
})