Redux Toolkit.
"Are you tired of dealing with complex boilerplate code and tedious setup when using Redux? Discover how Redux Toolkit can revolutionize your development experience by simplifying state management and supercharging your productivity. Dive into the world of Redux Toolkit and unlock a new level of efficiency and joy in your Redux-powered projects. Ready to say goodbye to the Redux headache?"
Note: If you are just jumping after the basic of react i.e state hooks its okay. You can directly jump to Redux Toolkit.
What is Redux Toolkit?
Redux Toolkit is a popular library that simplifies the development and management of Redux-based applications. It provides a set of utilities and abstractions that make it easier to write efficient and maintainable Redux code. Here are some reasons why Redux Toolkit is widely used:
Why Redux Toolkit?
Redux Toolkit provides a comprehensive set of tools and utilities that simplify and streamline the process of working with Redux. Here are some reasons why Redux Toolkit is a popular choice:
Simplicity: Redux Toolkit simplifies the usage of Redux by providing a cleaner API and predefined folder structure, reducing boilerplate code and making it more approachable for developers.
Built-in Immutability: Redux Toolkit integrates Immer to make working with immutable states easier, allowing developers to write mutable updates to states in a simpler syntax.
Automatic Redux DevTools Configuration: Redux Toolkit automatically sets up Redux DevTools Extension, enabling powerful debugging capabilities without additional configuration.
Efficient Slice Creation: Redux Toolkit introduces the concept of "slices" to encapsulate related state, reducers, and actions, simplifying code organization and reducing naming collisions.
Thunk Middleware Integration: Redux Toolkit includes
createAsyncThunk
to simplify handling asynchronous actions, automatically generating action creators for common async patterns.Opinionated Best Practices: Redux Toolkit incorporates recommended patterns and best practices, promoting maintainable and scalable Redux code and better code organization.
Difference Between Redux and Reduxtoolkit
Its official site is https://redux.js.org/
It was not organized.
We have to configure Redux DevTool Extension explicitly.
We need to manually handle and change the state immutably.
Configuring a Redux store is too complicated.
Need to create reducers and creators separately. Lots of boilerplate code.
Lots of code need to write to handle the asynchronous request and handling errors was also manual.
It is class based implementation.
Difference Between Redux and Reduxtoolkit
Its official site is https://redux-toolkit.js.org/
It is well organized.
It provides automatic support to Redux DevTool Extension.
It provides the support for Immer.js library which is automatically changes the code immutably.
Configuring a Redux store is much more easier and built in support of middleware.
A createSlice() function that comes handy to replace create action and create Reducer functions with a single function.
createAsyncThunk to make asynchronous request.
Functional implementation with Typescript and supports of Hooks.
Practical Implementation.
In this tutorial, we will create a product listing page and demonstrate how to implement Redux Toolkit for state management. We will explore the reasons why Redux Toolkit is used and how it addresses common challenges in state management.
Installation
react
reduxtoolkit
react-redux
Steps used in the counter app.
Inside index.js
Inside src folder create a file name index.js
and paste this code. Since the prerequisite says basic of react with state this code is not necessary for explanation.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Inside app.js
Inside src folder create a file name app.js
and paste this code. Since the prerequisite says basic of react with state this code is not necessary for explanation.
import './App.css';
import Home from './Home';
function App() {
return (
<div className="App">
App
</div>
);
}
export default App;
inside Home.js
Inside src folder create a file name Home.js and paste this code. Since the prerequisite says basic of react with state this code is not necessary for explanation.
import React from 'react'
const Home = () => {
const value= 20; /*creating variable for re-use */
return (
<div>
<h2>{value}</h2> /* Reusing variable as props */
<button>increase</button>
<button>increase by 500</button>
<button>decrease</button>
</div>
)
}
export default Home;
inside Store.js
import { configureStore } from "@reduxjs/toolkit";
const store =configureStore({
reducer:{ } //It is samecombined reducer in redux
})
export default store;
In the provided code snippet, we are configuring and creating a Redux store using Redux Toolkit's configureStore
function. The store is the central place where the application state is stored, and it is responsible for managing the state and handling actions in a Redux application.
The reducer
key specifies how the application state is managed and updated.In Redux, the state changes happen by dispatching actions, and the reducers define how the state should be updated based on these actions.
However, in the current code, the reducer
key is an empty object {}
. This means that there are no reducers defined at the moment. As a result, the state of the Redux store will not change in response to any dispatched
actions.
Notes:
Here we can say reducer is same as combined reducer in redux.
Multiple reducer is/ can be combine by reducer.
We can write reducer in same file also.
Reducer.js
For better practice we use as same as industry standard by creating separate file of Reducer.js
import { createReducer } from "@reduxjs/toolkit";
const initialState ={
c:0,
};
export const customReducer =createReducer(initialState, {
increment: (state, action)=>{ // we dont have to do action.type
state.c +=1;
},
incrementByValue: (state, action)=>{ // we dont have to do action.type
// state.c +=1;
state.c += action.payload;
},
decrement: (state, action)=>{ // we dont have to do action.type
state.c -=1;
},
})
Yes, you are absolutely correct! In Redux Toolkit's createReducer
, you no longer need to explicitly specify the action type for each case. Redux Toolkit internally takes care of generating the action type based on the key names you provide in the object argument.
The initialState
variable holds the initial state of the reducer. In this case, it contains a single field c
initialized to 0
.
The createReducer
function is used to create a reducer function named customReducer
. It takes two arguments: the initialState
and an object containing "case reducers." Each case reducer corresponds to a specific action type (which is automatically generated for you by Redux Toolkit).
For the action type
'increment'
, the state is updated by incrementing thec
field by1
.For the action type
'incrementByValue'
, the state is updated by adding thepayload
value to thec
field.For the action type
'decrement'
, the state is updated by decrementing thec
field by1
.
Notes:
Now with the help of redux toolkit we donot have to do action.type.
Here increment, incrementByValue, decrement are reducers that we can call whenever we need with the help of
dispatch.
inside Store.js
Importing customReducer from Reducer.js
import { customReducer } from "./Reducer";
reducer:{
custom: customReducer // we can give any name to custom
}
In this code, you are using customReducer
as the reducer function and giving it a name of 'custom'
in the reducer
configuration.
Notes: It is not necessary to give custom name ,we can give any name to custom
.
Inside index.js
import { Provider } from 'react-redux';
import store from './store';
<Provider store={store}>
<App />
</Provider>
Note:
The Provider
component makes the Redux store accessible to all connected components in a React application.
In a store there is a custom
(reducer), where initial state is 0, since till now we didnt call anything.
inside Home.js
import { useDispatch, } from 'react-redux';
const value= 20;
const dispatch = useDispatch();
const addBtn =()=>{
dispatch({
type:'increment',
})
};
const addBtn500 =()=>{
dispatch({
type:'incrementByValue',
payload: 500,
})
};
const subBtn =()=>{
dispatch({
type:'decrement',
})
};
<button onClick={addBtn}>increase</button>
<button onClick={addBtn500}>increase by 500</button>
<button onClick={subBtn}>decrease</button>
Note:
dispatch
is like a messenger that sends information (actions) to the Redux store to update the application state.
inside Home.js
import { useSelector } from 'react-redux';
const {c}= useSelector(state=> state.custom) // importing from store
// replacing value by c in h2 tag.
<h2>{c}</h2>
Note: 1. useSelector
is a React hook that allows functional components to access data from the Redux store easily.
Finalizing code in Each file.
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
app.js
import './App.css';
import Home from './Home';
function App() {
return (
<div className="App">
<Home/>
</div>
);
}
export default App;
inside store.js
import { configureStore } from "@reduxjs/toolkit";
import { customReducer } from "./Reducer";
const store =configureStore({
reducer:{
custom: customReducer
} //combined reducer in redux
})
export default store;
inside Reducer.js
import { createReducer } from "@reduxjs/toolkit";
const initialState ={
c:0,
};
export const customReducer =createReducer(initialState, {
increment: (state, action)=>{ // we dont have to do action.type
state.c +=1;
},
incrementByValue: (state, action)=>{ // we dont have to do action.type
// state.c +=1;
state.c += action.payload;
},
decrement: (state, action)=>{ // we dont have to do action.type
state.c -=1;
},
})
inside Home.js
import React from 'react'
import { useDispatch, useSelector } from 'react-redux';
const Home = () => {
// const value= 20;
const dispatch = useDispatch();
const {c}= useSelector(state=> state.custom)
const addBtn =()=>{
dispatch({
type:'increment',
})
}
const addBtn500 =()=>{
dispatch({
type:'incrementByValue',
payload: 500
})
}
const subBtn =()=>{
dispatch({
type:'decrement',
})
}
return (
<div>
<h2>{c}</h2>
<button onClick={addBtn}>increase</button>
<button onClick={addBtn500}>increase by 500</button>
<button onClick={subBtn}>decrease</button>
</div>
)
}
export default Home;
Jargons
Redux Toolkit is a popular library for simplifying the development of Redux applications. It provides several utility functions and abstractions that make working with Redux easier and more efficient. Here are some common jargons used in Redux Toolkit along with their definitions:
Slice: A slice is a portion of the Redux state that corresponds to a specific feature or domain of your application. It combines the reducer function and action creators related to that specific state section.
createSlice: A function provided by Redux Toolkit that generates a slice. It takes an initial state, an object with reducer functions, and automatically generates the corresponding action creators and action types.
Reducer: A function that takes the current state and an action and returns the new state. It should be a pure function, meaning it should not modify the original state, but create a new state object reflecting the changes.
Action Creator: A function that creates an action object. In Redux Toolkit, action creators are automatically generated for each case in the slice reducer.
Immutability: In Redux, state is immutable, meaning it cannot be changed directly. Instead, you create new state objects that represent the changes. Redux Toolkit uses Immer under the hood to simplify the process of updating immutable state.
createAsyncThunk: A function provided by Redux Toolkit that generates async action creators. It takes a string action type and an async function, and automatically generates action creators for pending, fulfilled, and rejected states of an asynchronous operation.
Thunk: A function that delays the evaluation of an expression. In the context of Redux, a thunk is a function returned by another function that can be used to perform async actions or side effects.
Entity Adapter: A utility provided by Redux Toolkit to simplify managing normalized entity data. It generates reducer functions and selectors for managing arrays of entities.
configureStore: A function provided by Redux Toolkit to create the Redux store. It automatically sets up the store with good defaults, including middleware for common use cases like Redux Thunk.
Middleware: Functions that can intercept and process actions before they reach the reducer. They are useful for implementing logging, asynchronous operations, or other side effects.
DevTools: Redux DevTools is a browser extension that helps visualize and debug Redux state changes.
Immutable Update Patterns: Techniques for creating new state objects with specific changes while keeping the original state immutable. Redux Toolkit abstracts this process using Immer, but common patterns include spreading objects and arrays, and using methods like
map
,filter
, andconcat
.Selector: A function that computes derived data from the Redux state. It allows you to extract specific information from the state in a memoized and efficient way.
These are some of the key jargon you'll encounter when working with Redux Toolkit. Understanding these terms will help you use Redux Toolkit effectively and efficiently in your application development.
Using Silice method.
store.js
// store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
counterSlice.js
// counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
value: 0,
};
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state) {
state.value += 1;
},
decrement(state) {
state.value -= 1;
},
incrementByAmount(state, action) {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
Home.js
// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';
function App() {
const dispatch = useDispatch();
const counterValue = useSelector((state) => state.counter.value);
const handleIncrement = () => {
dispatch(increment());
};
const handleDecrement = () => {
dispatch(decrement());
};
const handleIncrementByAmount = (amount) => {
dispatch(incrementByAmount(amount));
};
return (
<div>
<h1>Counter App</h1>
<div>
<button onClick={handleDecrement}>-</button>
<span>{counterValue}</span>
<button onClick={handleIncrement}>+</button>
</div>
<div>
<button onClick={() => handleIncrementByAmount(5)}>Increment by 5</button>
<button onClick={() => handleIncrementByAmount(-5)}>Decrement by 5</button>
</div>
</div>
);
}
export default App;
inside index.js
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
The end
Subscribe to my newsletter
Read articles from Roshan Guragain directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Roshan Guragain
Roshan Guragain
I am a Software developer who is passionate about making web app using the technologies like Html, Css, Javascript, React, Mongodb, Mongoose, Express, Node.