How to simplify Redux with Redux Toolkit

How to simplify Redux with Redux Toolkit

Get to know Redux Toolkit, a proven toolset for efficient Redux development. In this article, you’ll see why 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, over time, Redux's popularity declined due to:

  • Configuring Redux Store is not simple.
  • We need a few packages to make Redux work with React.
  • Redux requires too much boilerplate code.

With these questions, Dan Abramov, the creator of Redux, published an article titled "You May Not Need Redux", suggesting that people use Redux only when needed, and follow other methods when developing less complex applications.

Problems Redux Toolkit solves

Redux Toolkit (formerly Redux Starter Kit) provides options for configuring a global store and making creating actions and reducers more streamlined by abstracting the Redux API as much as possible.

What does it include?

Redux Toolkit comes with some useful packages like Immer, Redux-Thunk, and Reselect. It makes life much easier for React developers, allowing them to mutate state directly (without dealing with immutability), and apply middleware like Thunk (which handles asynchronous operations). It also uses Reselect, a simple "selector" library for Redux, to simplify the reducer function.

What are the main features of the Redux Toolkit API?

Following are the API functions used by Redux Took Kit, which is an abstraction of the existing Redux API functions. These functions do not change the Redux flows, they just simplify them in a more readable and manageable way.

  • configureStore: Creates a Redux store instance just like the original createStore from Redux, but accepts a named options object and automatically sets up the Redux DevTools extension.
  • createAction: Accepts an Action type string and returns an Action creation function that uses that type.
  • createReducer: Accepts the initial state value and a lookup table of action types to the reducer function and creates a reducer that handles all action types.
  • createSlice: accepts an initial state and a lookup table with reducer names and functions, and automatically generates action creator functions, action type strings, and a reducer function.

You can use the above API to simplify the boilerplate code in Redux, especially using the createAction and createReducer methods. However, this can be further simplified using createSlice, which automatically generates action creator and reducer functions.

What's special about createSlice?

It is a helper function that generates a memory slice. It accepts the name of the slice, the initial state, and a reducer function to return the reducer, action types, 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,
 });
};

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:
 return state;
 }
};
export default UserReducer;

Now, let's see how to simplify and achieve 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;

As you can see, now all actions and reducers are in one simple place, while in traditional redux application you need to manage each action and its corresponding action in reducer, when using createSlice you don't need to use switch to identify action.

A typical Redux flow will throw errors when it comes to mutating state, and you will need special JavaScript strategies like spread operator and Object assign to overcome them. Since Redux Toolkit uses Immer, you don't have to worry about mutating the state. Since slice creates actions and reducers, you can export them and use them in your components and Store to configure Redux without having to create 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,
 },
});

This store can be used directly from components via the redux api using useSelector and useDispatch. Note that you don't have to use any constants to identify the operations or use any types.

Handling asynchronous Redux flows

To handle asynchronous actions, Redux Toolkit provides a special API method called createAsyncThunk that accepts a string identifier and a payload creator callback, performs the actual asynchronous logic, and returns a Promise that will handle the dispatch of the associated action based on the Promise you return, and the action types that can be handled 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)
);

Unlike traditional data flows, the actions handled by createAsyncThunk will be handled by the extraReducers section within 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;

Note that inside the extraReducers you can handle both fulfilled and rejected states.

With these code snippets, you can see how well this toolkit can simplify your code in Redux. I created a REST example utilizing Redux Toolkit for your reference.

Final Thoughts

In my experience, Redux Toolkit is a great choice when getting started with Redux. It simplifies the code and helps manage the Redux state by reducing boilerplate code.

Finally, just like Redux, Redux Toolkit isn’t built just for React. We can use it with any other framework like Angular.

You can find more information by referring to the Redux Toolkit's documentation.

Thank you for reading!

The above is the details of how to use Redux Toolkit to simplify Redux. For more information about using Redux Toolkit to simplify Redux, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Implementation steps for setting up the React+Ant Design development environment
  • How to build a React project with Vite
  • React example of how to get the value of the input box
  • React implements the sample code of Radio component
  • Let's talk about my understanding and application of React Context
  • React hooks introductory tutorial
  • Detailed process of creating a VR panoramic project using React and Threejs
  • A brief talk about React Router's history
  • React uses routing to redirect to the login interface

<<:  Hbase Getting Started

>>:  MYSQL replaces the time (year, month, day) field with unchanged hours, minutes, and seconds. Example analysis

Recommend

A brief discussion on the solution of Tomcat garbled code and port occupation

Tomcat server is a free and open source Web appli...

How to configure two-way certificate verification on nginx proxy server

Generate a certificate chain Use the script to ge...

A brief discussion on the principle of js QR code scanning login

Table of contents The essence of QR code login Un...

How to forget the root password in Mysql8.0.13 under Windows 10 system

1. First stop the mysql service As an administrat...

How to implement Nginx reverse proxy for multiple servers

Nginx reverse proxy multiple servers, which means...

Detailed explanation of mkdir command in Linux learning

Table of contents Preface 1. Basic knowledge of f...

VMware15/16 Detailed steps to unlock VMware and install MacOS

VMware version: VMware-workstation-full-16 VMware...

Introduction and use of Javascript generator

What is a generator? A generator is some code tha...

Detailed explanation of the use of MySQL group links

Grouping and linking in MYSQL are the two most co...

How to deploy python crawler scripts on Linux and set up scheduled tasks

Last year, due to project needs, I wrote a crawle...

mysql wildcard (sql advanced filtering)

Table of contents First, let's briefly introd...

Brief analysis of the introduction and basic usage of Promise

Promise is a new solution for asynchronous progra...

Network configuration of Host Only+NAT mode under VirtualBox

The network configuration of Host Only+NAT mode u...

A brief discussion on several ways to pass parameters in react routing

The first parameter passing method is dynamic rou...