Setting up Redux using Redux Toolkit
anjalyyy1
Posted on June 12, 2022
In this blog we saw how to set up a global store using redux and react-redux. It is fine if you did not read that blog, but to understand better what problems redux toolkit is solving, it is recommended to read the previous blog.
Redux toolkit was introduced to solve the following problems which were there in the traditional approach of using redux:
- Setting up a Redux store was way too complicated
- You had to add a lot of packages to have redux do something useful.
- The developers had to write a lot of boilerplate code to just get started.
- Understanding the flow of data from the react components to the redux store and vice-versa was overwhelming for newbies.
- More code meant more surface area for bugs.
Let us now see how to setup redux with redux toolkit and how redux toolkit solves the above problems:
1. Install redux toolkit and react-redux
npm install @reduxjs/toolkit react-redux
We need @reduxjs/toolkit for the redux setup and react-redux so that react components and redux store could communicate.
2. Create a Redux Store
We will be creating two folders:
- redux (files related to redux configuration)
- store (files related to redux store)
Inside redux folder, we will create a file named createStore.js.
Inside this file, we use configureStore() for creating and configuring a store.
import { configureStore } from '@reduxjs/toolkit'
export const store = configureStore({
reducer: {},
})
configureStore is a friendly abstraction over the standard Redux createStore function and adds good defaults to the store set up for a better development experience.
It enables the Redux DevTools Extension automatically for better debugging and visualizing our store. Previously we had to install a separate module and write some code for this extension to work. It also enables redux-thunk, the most commonly used middleware for working with both synchronous and async logic outside of components, out of the box.
2. Provide the Redux Store to React
At the root level of our project, we will create a file named AllProvider.jsx where we will wrap our with , so that the entire store is available for the react components.
import GlobalStyle from "styles";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "redux/createStore";
const AllProvider = () => {
return (
<Provider store={store}>
<GlobalStyle />
<App />
</Provider>
);
};
export default AllProvider;
3. Create a Redux State Slice:
Inside our store folder, we can create a folder named slices.
For our counter reducer, we will create a file counter.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
value: 0,
};
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
// Action creators are generated for each case reducer function
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
This is the main file, which reduces the boilerplate to a great extent compared to the traditional approach. This is where the need to create action creators and types separately is no longer needed.
Redux state is typically organized into "slices". createSlice function will auto-generate the action types and action creators for us, based on the names of the reducer functions you provide. createSlice looks at all of the functions that are defined in the reducers field, and for every "case reducer" function provided, generates an action creator that uses the name of the reducer as the action type itself. Also now since immer library is in-built, we can get immutable updates with normal mutative code.
state.value += 1;
increment(1)
// {type : "counter/increment" }
4. Add Slice Reducers to the Store
Now, we need to import the reducer function from our counter slice and add it to our store.
import counterReducer from "store/slice/counter";
import { configureStore } from "@reduxjs/toolkit";
const rootReducer = {
counter: counterReducer,
};
export const store = configureStore({
reducer: rootReducer,
});
We kind of combine all our app reducers in the rootReducer object and pass it to configureStore(). As you can now see, the combineReducers() from the traditional approach is no longer needed now.
5.Using the actions and redux-store in our app
import { useDispatch, useSelector } from "react-redux";
import { increment, decrement } from "store/slice/counter";
const CounterComponent = () => {
const dispatch = useDispatch();
const counter = useSelector((state) => state.counter);
const incrementHandler = () => {
dispatch(increment());
};
const decrementHandler = () => {
dispatch(decrement());
};
return (
<div>
<button onClick={incrementHandler}>Increment by 1</button>
<button onClick={decrementHandler}>Decrement by 1</button>
</div>
);
};
export default CounterComponent;
The actions exported from the slice can be dispatched and the store data for the counter reducer is available as counter (as the key in rootReducer)
Now, any time you click the "Increment by 1" and "Decrement by 1" buttons:
- The corresponding Redux action will be dispatched to the store
- The counter slice reducer will see the actions and update its state
- The component will see the new state value from the store and re-render itself with the new data.
Now you know why has redux-toolkit become the recommended approach as it makes everything so easier and adds an abstraction over the things which should/could have been hidden.
Let me know if you have any questions in the comments below.
Happy coding!!!
Posted on June 12, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.