React with Redux - The Definitive guide.
Gautham Vijayan
Posted on June 26, 2023
In this post we will look into how we can integrate redux with React JS or Next JS for global state management of our web application. As our application grows, we will want to share the state across our application. In order to do this we can use a state management library called redux to manage our state across our application. So let's dive into it.
First, let's create a react project.
npx create-react-app redux-tutorial
cd redux-tutorial
Install the necessary libraries.
npm i react-redux redux redux-thunk
There are two things to do while learning redux.
- Understanding the concepts (In a theoretical manner),
- Implementation of the redux inside our application with hooks (if functional components are used)
Now let's look into the conceptual aspects of using redux. Redux has 4 terminologies associated with it..
- Actions
- Types
- Reducers
- Store
The store is used to store the state at a global level.
The Reducers are the functions which aid in manipulating the state.
The actions are the helper functions made by use to call the reducers to change the state.
The types are the names given by us to do state changes within the redux environment.
Now we will create the folders and the required files to integrate redux inside our application.
Create a folder structure like below.
Now we will be doing a small TODO application with redux here. We are going to name our reducers as todoReducer (you can name it anything like userReducer etc.)
We are going to create 2 Types and 2 Actions. The types will be,
- ADD
- DELETE
So lets create a file called TodoTypes.js and define the types there.
export const ADD_TODO = "ADD_TODO";
export const DELETE_TODO = "DELETE_TODO";
And 2 actions called,
- addTodoAction
- deleteTodoAction
(You can name the actions and reducers as you wish but I use this format which works fine.)
import { ADD_TODO, DELETE_TODO } from "../Types/TodoTypes";
export const addTodoAction = (data) => {
return {
type: ADD_TODO,
data: data,
};
};
export const deleteTodoAction = (data) => {
return {
type: DELETE_TODO,
data: data,
};
};
Now let's go to the todoReducer file and copy paste the below code.
import { ADD_TODO, DELETE_TODO } from "../Types/TodoTypes";
const initialState = {
todos: [{ name: "Redux", id: 1 }],
};
export const TodoReducers = (state = initialState, action) => {
switch (action.type) {
case ADD_TODO:
return { ...state, todos: [...state.todos, action.data] };
case DELETE_TODO:
return {
...state,
todos: state.todos.filter((item) => item.id !== action.data),
};
default:
return state;
}
};
So what is going on here?
We have made a switch case statement to handle the 2 TYPES we have created and update the state of the TODOS. So when we call an Action with a Type, the switch case statement conditionally sees the type which can be ADD or DELETE and performs the necessary state changes.
For example in the ADD Type, if a type called ADD is called from an action, the state gets updated to adding that todo item inside the todo list which is an array here.
Create a new file called Reducer.js and add the below code.
import { createStore, applyMiddleware } from "redux";
import { combineReducers } from "redux";
import thunk from "redux-thunk";
import { TodoReducers } from "./Reducers/TodoReducers";
const combinedReducers = combineReducers({
TodoReducers: TodoReducers,
});
const middleware = applyMiddleware(thunk);
const store = createStore(combinedReducers, middleware);
export { store };
So what I have done here is, I have imported the TodoReducers, and have used something called combineReducers function provided by redux. If we have multiple reducers, we can use this combineReducers to combine them and access them in the useSelector hook. Next I have applied redux thunk middleware and created a store and exported it. We will be using this to store the value in the global level by using a wrapper called in our root file.
Now Go to the index.js file or the file which is the root of your application and add the redux wrapper like this.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux'
import { store } from './Redux/Reducers';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
This is how you can use redux inside your React JS, Next JS or any other frontend frameworks and you can even use the same code in your react native application.
Now lets use the custom hooks provided by react-redux package to get the data stored in the global state and modify it as well.
So in the below code what we will be doing is we will be adding a todo and deleting it with help of dispatch by calling an action which we have setup earlier. And then we will use useSelector to get the data and show the todos to the user. We will be using map function because we initialised the todo state as an array. When the user presses on the submit button we call the addTodoAction and add the todo and if he presses on delete we delete the todo by filtering it with its unique id we have generated.
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addTodoAction, deleteTodoAction } from "./Redux/Actions/TodoActions";
function App() {
const [name, setName] = useState();
const dispatch = useDispatch();
const todoData = useSelector((state) =>state.TodoReducers);
return (
<div
style={{
margin: 200,
}}
>
<div>
<input
type="text"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
/>
</div>
<button
onClick={() => {
const todo = { id: Math.random(), name: name };
dispatch(addTodoAction(todo));
setName("");
}}
>
Submit
</button>
{todoData?.todos?.map((item, key) => {
return (
<div key={item?.id}>
{key + 1} . {item?.name}{" "}
<div
onClick={() => {
dispatch(deleteTodoAction(item?.id));
}}
>
Delete
</div>
</div>
);
})}
</div>
);
}
export default App;
This is how you create your redux folder structure and then you create your reducers, actions, types and use the custom hooks to modify and store data globally.
I feel by just reading this blog it will be tough to grasp all the concepts as it took me multiple weeks to even understand what is redux when i started out.
So, to know more in depth concepts about Redux integration with React JS & Next JS, you can view my course at Udemy with the below link. I would have discussed each and every step with visualising how the reducers work with actions to change the global state and how you can call backend APIs with useEffect and store the data in the global state. By the end of the course you will have full understanding on how to use redux for your projects.
Posted on June 26, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.