Introduction:
Redux Toolkit (RTK) is a set of utilities for Redux, a popular state management library for JavaScript applications. It provides a set of conventions and utilities that make it easier to build Redux applications by reducing the amount of boilerplate code you need to write. It structures our Redux code in a way that is easier to understand and maintain
Why Redux Toolkit?
The problem with vanilla redux is it's having a lot of boilerplate code, which most of the developers don't want to do, we have to write action creators again and again in vanilla redux. Also, it requires more libraries to make it more effective
Redux toolkit is a reincarnation of redux, it makes the developer's life so easy.
The reason for preferring the Redux toolkit:
- Less boilerplate code compared to vanilla redux
- No need to do extra setup for asynchronous operations,it has createAsyncThunk which will take care of it
- It's easy to understand, we can achieve the same functionality that vanilla redux provides in a very short and sweet way.
Since 2019 Redux Toolkit is the officially recommended approach to write any Redux code.
Installation:
We need to install two packages
npm install @reduxjs/toolkit react-redux
or
yarn add @reduxjs/toolkit react-redux
For creating a new React based Project with a Redux toolkit pre-installed
npx create-react-app my-app --template redux
Setup store
In Redux, a store is an object that holds the application's state.
It provides a way to access, update, and monitor the state. To create the store we have to import the configureStore function from the Redux toolkit.
Before configuring the store we have to create a redux reducer function that will specify how the state should be updated depending upon the actions triggered. Reducer function will take two arguments current state and action, it returns a new state depending upon the action.
Step 1: Implement createSilce method and export actions and reducer.
In Redux, a slice is a piece of the application's state that is managed by a specific reducer. Redux Toolkit provides the createSlice utility for creating slices of state and the corresponding reducer and action creators. createSlice takes an object that specifies the initial state, reducer functions, and action creators for the slice.
import { createSlice } from '@reduxjs/toolkit';
const todoListSlice = createSlice({
name: "todoList",
initialState: [],
reducers: {
addTodo: (state, action) => {
state.push(action.payload);
},
removeTodo: (state, action) => {
state.filter(todo => todo.id !== action.payload);
}
}
});
export const { addTodo, removeTodo } = todoListSlice.actions;
export default todoListSlice.reducer;
Step 2: Add Slice Reducers to the Store
In Redux, the configureStore function is a utility function provided by the redux-toolkit package that helps you set up a Redux store for your application. It takes a single argument, an options object, and returns a configured Redux store object.
import { configureStore } from '@reduxjs/toolkit';
import { combineReducers } from 'redux';
import todoList from 'todoListSlice';
const rootReducer = combineReducers({todoList}) which is similar to
const rootReducer = combineReducers({todoList:todoList})
If we want to use different attribute name then we can write like this
const example=combineReducers({attributeName:reducerName})
const store = configureStore({ devTools: true, reducer: rootReducer });
export default store;
We have to pass a single reducer function to our store, as the app grows more complex, you'll want to split your reducing function into separate functions, each managing independent parts of the state.
The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function.
for ex: const rootReducer=combineReducers({reducer1,reducer2,....,reducer-N})
The configureStore function accepts several options that allow you to customize the behavior of the store. Some common options include:
reducer: The root reducer of our application
devTools: This will allow us to inspect the state of our store
preloadedState: The initial state of the store.
Other than this there are many other options are vailable for configureStore. If you want more information about configureStore you can read the documentation here
Step 3: Connect our store to the app
Now we need to connect our store to the app. This will make our app access the redux store that we have created.
import { Provider } from 'react-redux';
import store from './redux/store';
.....
<Provider store={store}>
<App />
</Provider>
.....
Step 4: Read and update the global state using useSelector() and useDispatch() hooks
By using useSelector and useDispatch from react-redux, we can read the state from a Redux store and dispatch any action from a component, respectively.
useSelector():
useSelector is a function that takes the current state as an argument and returns whatever data you want from it.
import { useSelector } from 'react-redux';
const list = useSelector((state) => state.todoList);
// Here todoList is the attribute name given to the reducer
useDispatch():
If we want to modify the global state we need to use useDispatch and the action that we already created in slice.
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addTodo } from 'todoListSlice';
export default const MyTodoList=()=> {
const [text, setText] = useState('');
// We will invoke useDispatch and store it to a variable
const dispatch = useDispatch();
const addTodo = (e) => {
e.preventDefault();
// Here we are updating the todoList state by making use of the action that we have created in todoList slice
dispatch(addTodo(text));
setText('');
};
return (
<form onSubmit={addTodo}>
<input
type='text'
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button>Add todo</button>
</form>
);
}
If we want to remove the list from todoList we have to dispatch removeTodo action.
Handling asynchronous action in Redux toolkit
To perform asynchronous logic before sending the processed result to the reducers we have to make use of createAsyncThunk which is provided by toolkit
import { createSlice } from '@reduxjs/toolkit'
const asynchronousSlice = createSlice({
name: 'async',
initialState={
isLoading:false,
data:[],
isSuccess:false,
message:""
},
reducers: {},
extraReducers: {},
})
export default asynchronousSlice.reducer;
Within createSlice,synchronous requests are handled by reducer object and asynchronous requests are handled by extraReducer.
import { createAsyncThunk } from '@reduxjs/toolkit'
export const getData=createAsyncThunk("async/fetch",async(arg,thunkApi)=>{
const response=await fetch('url')
return response.data
})
This will create an action with async/fetch. The action will also have three additional properties pending, fulfilled, and rejected, which can be used to track the status of the async action. Depending upon this we can show a loading screen in UI to make it more user friendly
import { createSlice } from '@reduxjs/toolkit'
const asynchronousSlice = createSlice({
name: 'async',
initialState={
isLoading:false,
data:[],
isSuccess:false,
message:""
},
reducers: {},
extraReducers: {
[getData.pending]: (state) => {
state.isLoading = true
},
[getData.fulfilled]: (state, action) => {
state.isLoading = false
state.data = action.payload
state.isSuccess=true
},
[getData.rejected]: (state, action) => {
state.isLoading = false
state.message = action.error
}
},
})
export default asynchronousSlice.reducer;
Let's setup a component which will dispatch getData when it mounts.
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getData } from 'asynchronousSlice'
export default function Home() {
const dispatch = useDispatch()
const { data, isLoading } = useSelector((state) => state.async)
useEffect(() => {
dispatch(getData())
}, [])
if (loading) return <p>Loading...</p>
return (
<div>
<h2>Details</h2>
{data.map((post) => (
<p key={post.id}>{post.title}</p>
))}
</div>
)
}
Conclusion and Thoughts
Redux Toolkit can be a useful tool for reducing the amount of code you have to write when working with Redux, and for helping you structure your code in a way that is easier to understand and maintain.
Thanks for reading this article, and I hope you enjoyed reading it and learned something about Redux toolkit. Please leave a comment if you have any questions for me
Top comments (0)