As you know React
’s state has to be immutable. Otherwise, we are more likely to face some unwanted side effects when we try to mutate the state directly.
An immutable object is an object whose state cannot be modified after it is created.
Therefore, If you want to use standard JavaScript data structures to produce immutable states and to reduce the boilerplate code on your reducers then immer
(url) is tailored for you 💪
What we use so far when it comes to update our state in the reducers is the use of the spread operator.
Below you’ll find an example of what I mean:
const initialState = {
data: { color: 'red' }
}
const reducer = (state = initialState, action) => {
switch(action.type) {
case SET_COLOR:
return {
...state,
data {
...state.data,
color: 'yellow'
}
}
}
}
Is the above code considered outdated? Of course not! But when it comes to complex data structures and huge projects then the reducers are not simple like that one and they end up having a lot of boilerplate code making them hard to read.
This is where immer
comes in!
How it works
The magic lies to the produce
function that immer
has which allows us to create a draft object as a copy of our state but not the state itself. By modifying the draft object, we avoid mutating the original object.
The produce
function automatically returns a new state for us if we updated the draft
. The advantage is that we can modify the draft
as the way we do with normal javascript object or array.
Installation
You can install it by the following command:
npm install immer
Then, you can import it to your application:
import produce from 'immer';
Usage
import produce from 'immer';
const initialState = {
data: { color: 'red' }
}
const reducer = (state = initialState, action) => {
return produce(state, draft => {
switch(action.type) {
case SET_COLOR:
draft.data.color = 'yellow'
break;
}
})
}
Isn’t it way easier?
Advanced example:
Mutating an object by adding the color id as the key of the color object.
import produce from 'immer;
export default produce((draft, action) => {
switch (action.type) {
case ActionTypes.PopulateColors: {
draft.items = {};
action.payload.colors.forEach((color) => {
draft.items[color.id] = color;
});
break;
}
}
}, defaultState.colors);