Learn about the Redux Toolkit, a proven set of tools for effective Redux development. In this article, you’ll see why the Redux Toolkit deserves more attention from the React community.
React and Redux are considered the best combination for managing state in large-scale React applications. However, Redux’s popularity declined over time due to:
- Configuring the Redux Store is not easy.
- We need several packages to make Redux work with React.
- Redux requires too much boilerplate code.
With these questions in mind, Redux founder Dan Abramov published an article called “You Probably Don’t Need Redux,” advising people to use Redux only when they need it, and to follow other methods when developing less complex applications.
Problems solved by the Redux Toolkit
The Redux Toolkit(formerly known as the Redux Starter Kit) provides options for configuring global Stores and creating actions and reducers more streamlined by abstracting the Redux API as much as possible.
What does it include?
The Redux Toolkit comes with some useful packages such as Immer, Redux-Thunk, and Reselect. It makes life easier for React developers, allowing them to change state directly (without dealing with immutability) and apply middleware like Thunk (which handles asynchronous operations). It also uses Reselect, a simple “selector” library from Redux, to simplify the Reducer function.
What are the key functions of the Redux Toolkit API?
The following API functions used by the Redux Took Kit are abstractions of existing Redux API functions. These functions do not change the flow of Redux, just simplify them in a more readable and manageable way.
- ConfigureStore: Create an instance of Redux Store just as the original createStore was created from Redux, but accept a named option object and automatically set the Redux DevTools extension.
- CreateAction: takes an Action string and returns an Action creation function that uses that type.
- CreateReducer: Accepts the initial state values and lookup tables of Action types into the Reducer function and creates a Reducer that handles all Action types.
- CreateSlice: Takes an initial state and a lookup table with a Reducer name and function, and automatically generates the Action Creator function, the action type string, and a Reducer function.
You can use the API above to simplify boilerplate code in Redux, especially with the createAction and createReducer methods. However, this can be further simplified using createSlice, which automatically generates the Action Creator and Reducer functions.
What’s so special about createSlice?
It is a helper function that generates a memory slice. It accepts the slice name, initial state, and the Reducer function to return the Reducer, action type, and Action Creators.
First, let’s look at what reducers and Actions look like in a traditional React-Redux application.
Actions
import {GET_USERS,CREATE_USER,DELETE_USER} from ".. /constant/constants";
export const GetUsers = (data) = > (dispatch) = > {
dispatch({
type: GET_USERS,
payload: data,
});
};
export const CreateUser = (data) = > (dispatch) = > {
dispatch({
type: CREATE_USER,
payload: data,
});
};
export const DeleteUser = (data) = > (dispatch) = > {
dispatch({
type: DELETE_USER,
payload: data,
});
};
Copy the code
Reducers
import {GET_USERS,CREATE_USER,DELETE_USER} from ".. /constant/constants";
const initialState = {
errorMessage: "".loading: false.users:[]
};
const UserReducer = (state = initialState, { payload }) = > {
switch (type) {
case GET_USERS:
return { ...state, users: payload, loading: false };
case CREATE_USER:
return { ...state, users: [payload,...state.users],
loading: false };
case DELETE_USER:
return { ...state,
users: state.users.filter((user) = >user.id ! == payload.id), , loading:false };
default:
returnstate; }};export default UserReducer;
Copy the code
Now, let’s see how you can simplify and implement the same functionality using createSlice.
import { createSlice } from '@reduxjs/toolkit';
export const initialState = {
users: [].loading: false.error: false};const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
getUser: (state, action) = > {
state.users = action.payload;
state.loading = true;
state.error = false;
},
createUser: (state, action) = > {
state.users.unshift(action.payload);
state.loading = false;
},
deleteUser: (state, action) = > {
state.users.filter((user) = >user.id ! == action.payload.id); state.loading =false; ,}}});export const { createUser, deleteUser, getUser } = userSlice.actions;
export default userSlice.reducer;
Copy the code
As you can see, all actions and reducer are now in one simple place, whereas in a traditional Redux application you need to manage each action and its corresponding action in the Reducer, and when using createSlice you do not need to use switches to identify actions.
A typical Redux process throws errors when it comes to mutated state, and you’ll need special JavaScript strategies such as spread Operator and Object assign to overcome them. Because the Redux Toolkit uses Immer, you don’t have to worry about changing state. Since Slice creates Actions and Reducers, you can export them and use them in your components and stores to configure Redux without having to set up separate files and directories for Actions and Reducers, as shown below.
import { configureStore } from "@reduxjs/toolkit";
import userSlice from "./features/user/userSlice";
export default configureStore({
reducer: {
user: userSlice,
},
});
Copy the code
This storage can be used directly from components using the Redux API of useSelector and useDispatch. Note that you do not have to use any constants to identify an operation or use any type.
Process asynchronous Redux streams
To handle asynchronous actions, the Redux Toolkit provides a special API method called createAsyncThunk, which takes a string identifier and a payload creator callback, executes the actual asynchronous logic, and returns a Promise, The Promise will handle scheduling of related actions based on the Promise you return, as well as the types of actions you can handle in your Reducers.
import axios from "axios";
import { createAsyncThunk } from "@reduxjs/toolkit";
export const GetPosts = createAsyncThunk(
"post/getPosts".async() = >await axios.get(`${BASE_URL}/posts`));export const CreatePost = createAsyncThunk(
"post/createPost".async (post) => await axios.post(`${BASE_URL}/post`, post)
);
Copy the code
Unlike traditional data streams, actions handled by createAsyncThunk will be handled by the extraReducers part of the shard.
import { createSlice } from "@reduxjs/toolkit";
import { GetPosts, CreatePost } from ".. /.. /services";
export const initialState = {
posts: [].loading: false.error: null};export const postSlice = createSlice({
name: "post".initialState: initialState,
extraReducers: {
[GetPosts.fulfilled]: (state, action) = > {
state.posts = action.payload.data;
},
[GetPosts.rejected]: (state, action) = > {
state.posts = [];
},
[CreatePost.fulfilled]: (state, action) = >{ state.posts.unshift(action.payload.data); ,}}});export default postSlice.reducer;
Copy the code
Note that inside the extraReducers, you can deal with the fulfilled and rejected states.
With these code snippets, you can see how well the toolkit simplifies code in Redux. I’ve created a REST example that utilizes the Redux Toolkit for your reference.
Final thoughts
In my experience, the Redux Toolkit is a good choice when starting out with Redux. It simplifies code and helps manage Redux state by reducing template code.
Finally, just like Redux, the Redux Toolkit is not built just for React. We can use it with any other framework, such as Angular.
You can find more information by referring to the documentation for the Redux Toolkit.
Thank you for reading!
Translated from blog.bitsrc. IO by Madushika Perera
More articles
- Rust and Python: Why can Rust replace Python
- Use RoughViz to visualize sketch charts in vue.js
- Programming calendar applets, applets for cloud development and generating sharing poster practices
- Improve application performance and code quality: compose HTTP requests through proxy patterns
- Object – oriented programming is the biggest mistake in computer science
- Translation | make HTML 5 digital input only accept an integer
- 13 top free WYSIWYG text editor tools