Redux is one of the most popular state-maintaining libraries for React Applications. Redux allows you to manage and update the application’s data state within one place and later share it with different components. In other words, when you add Redux to your React app, It loads, saves, and tracks the changes of application data in one place and transfers the required data to any components.
In this article, we will understand 6 simple steps you can apply in order to add Redux to your React application.
Why you need Redux
As Javascript applications are getting big and more complex, it has become a great menace to manage different data states in multiple components that might need at the same time. The data state may include multiple server responses, cached Data, and locally created data. Thus, managing an ever-changing state is hard.
Reasons to use Redux
The same Data need to map to multiple components
In a great app, there is a high chance that two or more components might need the same data one at a time or at the same time. So in that case, you might need to recalculate the same business logic for two different components which eventually makes your app slow.
Global state data that can be accessed from anywhere
You may also need to send the same data to two different children under different parents, then it may require you to use too many props to pass through multiple hierarchies of components.
Cached page data
If the user opens a page that calls API to display some data, and then the user moves to a different page but comes back, then the app has to call back the API again to display the data as we didn’t have any means to cache that data, your app has to work multiple time.
Also read, How Does React Js works | Detail Explanation on Virtual DOM
Understanding the basic concepts of Redux
Before we begin adding Redux to your app, it is necessary for you to get familiar with a few Redux concepts,
Store
As the name suggests, Store is an object that acts as a storehouse where all the global state data which you think other components might share is saved in one place. Your app can access the store but can’t directly change it.
Note:- There should be only a single Store for an application.
Actions
In order to update/change the state of the store, you need to dispatch an action. An action is a plain Javascript object consisting of a type and optional data which you want to update the state of the store.
{ type: 'ADD_TODO', text: 'Need to Study' }
Reducers
A Reducer is a place where you write the business logic and update the state of the app. Basically, a Reducer is a JavaScript pure function that receives a global state, and all the actions as an argument, we write the business logic and return the new updated global state.
Also read, How to select only one element of a map() in React
Adding Redux to your React App in simple 6 steps
You can easily add Redux to your React app by following the below 6 steps:-
- Install required libraries
- To Subscribe,
- Setup Action Types
- Setup Action functions
- Setup Reducer
- Create a Redux store
- Subscribe to your app to receive all the updates
- If necessary, render the UI with an initial state
- Respond to UI updates by dispatching Redux actions
In order to demonstrate, let us create a Todo app, where we use redux to add or delete tasks,
Install required libraries
Before we move forward with Redux, we need to install a few libraries to setup Redux in our app,
npm i redux react-redux @reduxjs/toolkit
Create Actions Types, Action Functions, and Reducers
Action Types
Before creating Action and Reducer functions, first we need to set up Actions types and save them in the constants.js file, for our Todo apps, our action Type looks like this,
// for tasks
export const GET_ALL_TASK = "GET_ALL_TASK";
export const CREATE_NEW_TASK = "CREATE_NEW_TASK";
export const DELETE_TASK = "DELETE_POST";
export const TASK_COMPLETED = "TASK_COMPLETED";
export const TASK_PENDING = "TASK_PENDING";
Also read, A simple React Hook Form Validation with Formik and Yup
Action Function
Now let us move on to creating Action Function, In order to mutate the data state, you need to dispatch the action function.
import {
GET_ALL_TASK,
CREATE_NEW_TASK,
DELETE_TASK,
TASK_COMPLETED,
TASK_PENDING
} from "./constants";
// Action function to add new task to the task list
export const addTask = (data) => {
return {
type: GET_ALL_TASK,
task: data
};
};
Reducer Function
In the Reducer function, we pass two arguments, one is the internal Data state which is passed towards all the components of React app, and dispatched action functions. Using Action types, different business logic is chosen, where we update the state and pass the newly updated state.
import {
GET_ALL_TASK,
CREATE_NEW_TASK,
DELETE_TASK,
TASK_COMPLETED,
TASK_PENDING
} from "./constants";
// Internal Data State of the Store
const initialState = {
allTask: [
{
id: 1,
task: "Study",
status: "completed"
},
{
id: 2,
task: "Work",
status: "pending"
},
{
id: 3,
task: "Gym",
status: "pending"
}
]
};
// Reducers to update the Internal function
const TaskReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ALL_TASK:
let tsk = {
id: Math.floor(Math.random() * 100),
task: action.task,
status: "pending"
};
return {
...state,
allTask: [...state.allTask, tsk]
};
default:
return state;
}
};
export default TaskReducer;
Also read, React Lifecycle Methods | Detail Explanation with Diagram
Create a Redux store
Now Finally it is time to set up your store,
import { createStore } from "redux";
import TaskReducer from "./reducer";
const store = createStore(TaskReducer);
export default store;
Also read, Learning to Think Like a Computer
Subscribe to your app to receive all the updates
React-Redux provides <Provider/>
component and pass the store you created in store.js
, which makes the Redux store available for the rest of the store.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import store from "./Redux/store";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
);
Render the UI with an Initial State
With the help of useSelector hooks, which reads and subscribe the data from the store state, we renders the list of default task present in the store state.
import React, { useState } from "react";
import "./styles.css";
import { IoCloseCircleSharp } from "react-icons/io5";
import { useSelector } from "react-redux";
export default function App() {
// With 'useSelector' hook, we derive all
// the present task in the state store
const data = useSelector((state) => state.allTask);
const [inputTask, setInputTask] = useState();
return (
<div className="App">
<div className="header">
<h1>Todo App - Redux</h1>
</div>
<div className="input-area">
<input
className="input"
type="text"
placeholder="Add New Task"
/>
<button className="input-btn">
Submit
</button>
</div>
<div className="task-display">
<h2>
<strong>Tasks</strong>
</h2>
<div className="task-container">
{data.map((item) => {
return (
<div className="tasks" key={item.id}>
<div className="task-left">
<input type="checkbox" />
<p>{item.task}</p>
</div>
<div className="remove-btn">
<IoCloseCircleSharp />
</div>
</div>
);
})}
</div>
</div>
</div>
);
}
Respond to UI updates by dispatching Redux actions
When the user wants to add a new task to the list, we use the useDispatch
hook to dispatch the function in order to update the initial list of tasks present in-store state and add a new task to it.
import React, { useState } from "react";
import "./styles.css";
import { IoCloseCircleSharp } from "react-icons/io5";
import { useDispatch, useSelector } from "react-redux";
import { addTask } from "./Redux/actions";
export default function App() {
// With the help of dispatch function,
// we can add new task to store.
const dispatch = useDispatch();
// With 'useSelector' hook, we derive all
// the present task in the state store
const data = useSelector((state) => state.allTask);
// With the 'useState' hook we capture input
// data from the input tag.
const [inputTask, setInputTask] = useState();
const submit = () => {
// Here, we dispatch 'addTask' dispatch functions
// to update the task list.
dispatch(addTask(inputTask));
};
return (
<div className="App">
<div className="header">
<h1>Todo App - Redux</h1>
</div>
<div className="input-area">
<input
className="input"
type="text"
placeholder="Add New Task"
value={inputTask}
onChange={(e) => setInputTask(e.target.value)}
/>
<button className="input-btn" onClick={submit}>
Submit
</button>
</div>
<div className="task-display">
<h2>
<strong>Tasks</strong>
</h2>
<div className="task-container">
{data.map((item) => {
return (
<div className="tasks" key={item.id}>
<div className="task-left">
<input type="checkbox" />
<p>{item.task}</p>
</div>
<div className="remove-btn">
<IoCloseCircleSharp />
</div>
</div>
);
})}
</div>
</div>
</div>
);
}
App Demo
Here is a small demo of our ToDo app,
Also read, Simple tutorial on React authentication with redux + Example
Final Words
If you have an extensive complex application, where two or more components need the same type of data, instead of calling API for each element you can use Redux where your API data get called once and get stored for the rest of the components to use. In starting understanding Redux can be a little overwhelming, and it has a difficult learning curve but if you use it often, then managing Redux becomes very easy and efficient.
I hope you like my article, and if you did !! Please share it more with your colleagues and friends, also bookmark and subscribe to never miss our article! Also, do share amazing articles on various domains like Data Structure and algorithms, React, Java, and much more.