I'm setting up a reducer using Redux Toolkit & Immer using the guide here. Using this we can do immutable updates to the state which look like mutations.
However, it's not clear to me if I'm allowed to "mutate" the payload too, as with the example below:
export default interface Song {
name: string;
content: string;
lastPopulated: number;
}
const initialState = {
songs: [] as Song[]
}
const updateSong = createAction<Song>('song/updateSong');
const rootReducer = createReducer(initialState, (builder) => {
builder
.addCase(updateSong, (state, action) => {
const newSong = action.payload;
newSong.lastPopulated = Date.now(); // Is this allowed???????
state.songs = state.songs.map(
song => song.name === newSong.name ? newSong : song
);
})
});
Is that permitted or do I instead need to do something like this?:
const newSong = {
...action.payload
lastPopulated = Date.now();
}
CodePudding user response:
Mutating the action do not make much sense. They are actually events. Something that happened in the past. They are facts, they should not mutate at all.
Use the action to mutate the state, and only the state.
CodePudding user response:
It's legal, technically, although it sort of depends on where the payload value came from in the first place.
For example, say that you did dispatch(somethingHappened(someValueFromState))
. In that case, action.payload
is the same reference as something that is currently in the Redux store state, and if you mutate it, you're actually mutating the existing state. That would be incorrect and break things.
But, if the action payload value was a new object, something created by the code that did the dispatching, then it would be fine - no other code is looking at that object and doing something with it.
All things considered, though, I'd generally suggest avoiding this and go with the immutable copying approach you showed at the end. That way it's very clear what you're doing, and you avoid any potential issues.
Alternately, you could insert the payload value into the state, and then "mutate" it, and Immer should wrap the value like any other state value and handle the update immutably.