What is redux?
Redux is a JavaScript library for managing the application state. It is a predictable state container that allows you to write applications that behave consistently no matter what changes the state.
Most of us are using redux in multiple projects, I've also used it in multiple projects. It's easy to use, and it's easy to understand, One thing I don't like is a lot of boilerplate code. Let's try to understand with a simple example.
I'm not going to cover redux setup details here
Step:
Install react-redux and redux using npm
// Store.ts
import { combineReducers, createStore } from "redux";
// Reducer file
const counterReducer = (state = 0, { type, payload }) => {
switch (type) {
case "INCREMENT":
return state + payload;
case "DECREMENT":
return state + payload;
default:
return state;
}
};
// Action creator file
export const increment = (payload) => ({ type: "INCREMENT", payload });
export const decrement = (payload) => ({ type: "DECREMENT", payload });
// Store entrypoint file
const reducers = () =>
combineReducers({
counter: counterReducer,
});
const store = createStore(reducers());
export default store;
NOTE: every section can be moved to a different file. I'm trying to keep it simple.
App.ts
export default function App() {
const state = useSelector((state: any) => state);
const dispatch = useDispatch();
return (
<div>
<h1>Count: {state.counter}</h1>
<button onClick={() => dispatch(increment(1))}>Increment</button>
<button onClick={() => dispatch(decrement(-1))}>Decrement</button>
</div>
);
}
index.ts
<Provider store={store}>
<App />
</Provider>
You might be wondering what is wrong with this approach. There is no problem with this approach In this example, We have only 2 actions it looks simple but in the real world, we have a lot of actions. You have to create a separate action creator function for all. I don't like it because all the function has almost the same code except the action name. It would be great if all the action creators can be generated automatically.
How can we generate action creators automatically?
The first thing you have to do is update the structure of your reducer, Instead of using a switch case, you should use an object.
An object is a better way to manage your reducer, It's faster and easier to read. I don't like switch cases, I prefer objects.
Switch can have a time complexity of O(n) where n is the number of cases. An object has a time complexity of O(1). check here some other best practices
Reducer file
const counterReducerMap = {
increment: (state, { payload }) => state + payload,
decrement: (state, { payload }) => state + payload,
};
const counterReducer = (state = 0, action) => {
const handler = counterReducerMap[action.type];
return handler ? handler(state, action) : state;
};
Let's create generic action creator function
const createAction = <T>(reducers): T => {
return Object.keys(reducers).reduce((acc, type) => {
acc[type] = (payload) => ({
type,
payload,
});
return acc;
}, {} as T);
};
export const { increment, decrement } = createAction(counterReducerMap);
You can remove generic type if you are using javascript.
NOTE: Import thing to notice here is reducer map keys are your action creator functions. It's not a reducer function.
If you follow this approach, you can reduce a lot of boilerplate code. This approach will also reduce production bundle size.
Bonus for typescript developers
type ActionCreator<A> = {
[key in keyof A]: <T>(payload: T) => {
type: key;
payload: T;
};
};
type Action = ActionCreator<typeof counterReducerMap>;
export const { increment, decrement } = createAction<Action>(counterReducerMap);
Live Example: here
Thank you for reading 😊
Got any questions or additional? please leave a comment.
Top comments (2)
Great article!
One doubt here: