Redux is a very popular solution for state management in React applications. I also work a lot with this library and in this short article, I want to share a way how we can use object notation to check our action types.
In most cases, developers use 2 common ways to iterate through the action types. The first approach is to use if else
construction. It can be useful for small reducers, where we have just one or two conditions. Here is an example of such a case:
const SAVE_USER_NAME = 'SAVE_USER_NAME';
export const reducer = (state, { type, payload }) => {
if (type === SAVE_USER_NAME) {
return {
...state,
name: payload,
};
}
return state;
};
We have just one action type SAVE_USER_NAME
. And in our reducer we use if
construction to check the current action type. When it’s equal to true - we return the new state, when not - we just return the initial state. This is a good approach, but it will not be so nice when we have a couple of different action types. In this situation, another very popular solution which is used everywhere is switch
construction. It allows us to iterate through a huge number of action types without if else
. Example of this solution:
const SAVE_USER_NAME = 'SAVE_USER_NAME';
const SAVE_USER_EMAIL = 'SAVE_USER_EMAIL';
const SAVE_USER_ADDRESS = 'SAVE_USER_ADDRESS';
export const reducer = (state, { type, payload }) => {
switch (type) {
case SAVE_USER_NAME:
return { ...state, name: payload };
case SAVE_USER_EMAIL:
return { ...state, email: payload };
case SAVE_USER_ADDRESS:
return { ...state, address: payload };
default:
return state;
}
};
It looks much better than if we use a lot of else if
. But in my experience sometimes I had to deal with reducers where we have 40 or even 60 ‘cases’. And, as we have used SonarQube in our CI/CD pipeline, it started to send many alerts because there were too many ‘cases’ in switch
block. So how we can fix this?
The first thing that we can do is to split our big reducer into several smaller ones. But what if we don’t want to do this or we don’t have enough time? Do we have another way how to refactor this reducer and remove switch
?
Yeah, we have. And here we can use objects. I’m a big fan of objects, and hash maps, and I just refactored the previous solution:
const SAVE_USER_NAME = 'SAVE_USER_NAME';
const SAVE_USER_EMAIL = 'SAVE_USER_EMAIL';
const SAVE_USER_ADDRESS = 'SAVE_USER_ADDRESS';
export const reducer = (state, { type, payload }) => {
const actionTypes = {
[SAVE_USER_NAME]: () => ({
...state,
name: payload,
}),
[SAVE_USER_EMAIL]: () => ({
...state,
email: payload,
}),
[SAVE_USER_ADDRESS]: () => ({
...state,
address: payload,
}),
};
return actionTypes[type] ? actionTypes[type]() : state;
};
We’ve created actionTypes
object, where a key is our action type and value is a function. Then we check, if such a key exists - we execute the function, else - we just return the initial state. I personally like this approach. It looks elegant and easy to read.
What do you think of this way? Do you use such an approach or maybe something else?
P.S: It’s my first article, so I hope that it will be interesting and don’t throw tomatoes at me 😄