Issue
I have the following createSlice
code where there is the reducer setCustomEquipment
that modifies the state. Is the =
approach a valid way to mutate the state when using createSlice
, or should I use the shallow state copy approach anyway regardless of whether I am using createSlice
or not?
export const someSlice = createSlice({
name: 'some',
initialState,
reducers: {
setCustomEquipment: (state, action: PayloadAction<CustomEquipment[]>) => {
// Variant A
state.customEquipment = action.payload;
// Variant B
// return {
// ...state, { state.customEquipment : action.payload }
// }
},
Solution
Either method you are using is fine, and entirely your decision.
Mutable update
setCustomEquipment: (state, action: PayloadAction<CustomEquipment[]>) => {
state.customEquipment = action.payload;
}
Return shallow copy into new reference
setCustomEquipment: (state, action: PayloadAction<CustomEquipment[]>) => {
return {
...state,
customEquipment: action.payload,
};
}
When using Redux-Toolkit slice reducers the allowed methods of updating state are to write mutable state update or to return a new state reference, e.g. a shallow copy of the previous state with overwritten properties.
See Direct State Mutation for details.
To make things easier,
createReducer
uses immer to let you write reducers as if they were mutating the state directly. In reality, the reducer receives a proxy state that translates all mutations into equivalent copy operations.
Writing "mutating" reducers simplifies the code. It's shorter, there's less indirection, and it eliminates common mistakes made while spreading nested state. However, the use of Immer does add some "magic", and Immer has its own nuances in behavior. You should read through pitfalls mentioned in the immer docs. Most importantly, you need to ensure that you either mutate the
state
argument or return a new state, but not both.
From the pitfalls:
Don't reassign the recipe argument
Never reassign the draft argument (example:
draft = myCoolNewState
). Instead, either modify the draft or return a new state.
So basically the anti-patterns are:
Mutating draft state object and returning a new state reference
setCustomEquipment: (state, action) => { state.otherPropery = "foo"; return { ...state, property: action.payload, }; }
Reassignment of the current state draft object
setCustomEquipment: (state, action) => { state = { ...state, otherPropery: "foo", property: action.payload, }; }
Answered By - Drew Reese
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.