How to Optimize the Performance of React-Redux Applications?
Last Updated :
24 May, 2024
Optimizing the performance of React-Redux applications involves several strategies to improve loading speed, reduce unnecessary re-renders, and enhance user experience. In this article, we implement some optimization techniques, that can significantly improve the performance of applications.
We will discuss the different approaches to optimize the performance of React-Redux applications:
Steps to Create a React App and Installing Module
Step 1: Create a React application using the following command.
npx create-react-app redux-app
Step 2: After creating your project folder i.e. redux-app, move to it using the following command.
cd redux-app
Step 3: Install required dependencies like redux, and reselect.
npm i react react-dom redux react-redux reselect
Project Structure:
Project Structure
The Updated dependencies in your package.json file is:
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"reselect": "^5.1.0"
}
Use useSelector Wisely
The useSelector hook can cause unnecessary re-renders if not used properly. Make sure you are selecting only the necessary part of the state.
Example: Below is an example to optimize the performance of React-Redux applications using Reselect Library.
CSS
/* App.css */
button {
background-color: rgb(228, 233, 224);
border: 1px solid transparent;
cursor: pointer;
padding: 10px 20px;
margin: 10px;
}
button:hover {
background-color: rgb(77, 197, 77);
}
input,
select {
padding: 10px 20px;
margin: 5px;
}
#App{
display: flex;
flex-direction: column;
align-items: center;
}
JavaScript
// App.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addUser } from './store';
import './App.css'
// UserDetails Component
let count = 1;
const UserDetails = () => {
const dispatch = useDispatch();
const handleAddUser = () => {
const newUser = { name: `User ${count++}` };
dispatch(addUser(newUser));
};
return <button onClick={handleAddUser}>Add User</button>;
};
// UserList Component
const UserList = () => {
const users = useSelector((state) => state.users);
return (
<ul>
{users.map((user, index) => (
<li key={index}>{user.name}</li>
))}
</ul>
);
};
// App Component
const App = () => {
return (
<div>
<UserDetails />
<UserList />
</div>
)
};
export default App;
JavaScript
// store.js
import { createStore } from 'redux';
// Action types
const ADD_USER = 'ADD_USER';
// Action creators
export const addUser = (user) => ({
type: ADD_USER,
payload: user,
});
// Initial state
const initialState = {
users: [],
};
// Reducer
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_USER:
return {
...state,
users: [...state.users, action.payload],
};
default:
return state;
}
};
// Create store
const store = createStore(reducer);
export default store;
JavaScript
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Output :
Use Selector Output
Normalize State
Ensure your Redux state shape is normalized. This reduces the complexity of your state and helps in efficiently updating and accessing it.
Example: Below is an example to optimize the performance of React-Redux applications using Reselect Library.
CSS
/* App.css */
button {
background-color: rgb(228, 233, 224);
border: 1px solid transparent;
cursor: pointer;
padding: 10px 20px;
margin: 10px;
}
button:hover {
background-color: rgb(77, 197, 77);
}
input,
select {
padding: 10px 20px;
margin: 5px;
}
#App{
display: flex;
flex-direction: column;
align-items: center;
}
JavaScript
// store.js
import { createStore } from 'redux';
import { combineReducers } from 'redux';
// Action Types
const ADD_COMMENT = 'ADD_COMMENT';
const UPDATE_COMMENT = 'UPDATE_COMMENT';
const DELETE_COMMENT = 'DELETE_COMMENT';
// Action Creators
export const addComment = (comment) => ({
type: ADD_COMMENT,
payload: comment,
});
export const updateComment = (id, changes) => ({
type: UPDATE_COMMENT,
payload: { id, changes },
});
export const deleteComment = (id) => ({
type: DELETE_COMMENT,
payload: id,
});
// Initial State
const initialCommentsState = [];
// Comments Reducer
const commentsReducer = (state = initialCommentsState, action) => {
switch (action.type) {
case ADD_COMMENT:
return [...state, action.payload];
case UPDATE_COMMENT:
return state.map(comment =>
comment.id === action.payload.id
? { ...comment, ...action.payload.changes }
: comment
);
case DELETE_COMMENT:
return state.filter(comment => comment.id !== action.payload);
default:
return state;
}
};
// Root Reducer
const rootReducer = combineReducers({
comments: commentsReducer,
});
// Create Store
const store = createStore(rootReducer);
export default store;
JavaScript
// App.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addComment, updateComment, deleteComment } from './store';
import './App.css'
const App = () => {
const dispatch = useDispatch();
const comments = useSelector(state => state.comments);
const handleAddComment = () => {
const newComment = {
id: Date.now().toString(),
content: 'New Comment'
};
dispatch(addComment(newComment));
};
const handleUpdateComment = (id) => {
const updatedComment = { content: 'Updated Comment' };
dispatch(updateComment(id, updatedComment));
};
const handleDeleteComment = (id) => {
dispatch(deleteComment(id));
};
return (
<div>
<h1>
<img src='https://media.geeksforgeeks.org/gfg-gg-logo.svg' alt='gfg_logo' />{" "}
Comments
</h1>
<button onClick={handleAddComment}>Add Comment</button>
<ul>
{comments.map((comment) => (
<li key={comment.id}>
{comment.content}
<button onClick={
() => handleUpdateComment(comment.id)}>
Update
</button>
<button onClick={
() => handleDeleteComment(comment.id)}>
Delete
</button>
</li>
))}
</ul>
</div>
);
};
export default App;
JavaScript
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Output:
Normalize State Output Split Reducers
Break down your reducers to handle smaller slices of state. This can make state management more efficient and avoid re-rendering.
Example: Below is an example to optimize the performance of React-Redux applications using Reselect Library.
CSS
/* App.css */
button {
background-color: rgb(228, 233, 224);
border: 1px solid transparent;
cursor: pointer;
padding: 10px 20px;
margin: 10px;
}
button:hover {
background-color: rgb(77, 197, 77);
}
input,
select {
padding: 10px 20px;
margin: 5px;
}
#App{
display: flex;
flex-direction: column;
align-items: center;
}
JavaScript
// store.js
import { createStore, combineReducers } from 'redux';
// Action types
const ADD_TASK = 'ADD_TASK';
const ADD_CATEGORY = 'ADD_CATEGORY';
// Action creators
export const addTask = (task) => ({ type: ADD_TASK, payload: task });
export const addCategory = (category) => ({ type: ADD_CATEGORY, payload: category });
// Initial state
const initialTasksState = { tasks: {} };
const initialCategoriesState = { categories: {} };
// Tasks reducer
const tasksReducer = (state = initialTasksState, action) => {
switch (action.type) {
case ADD_TASK:
return {
...state,
tasks: { ...state.tasks, [action.payload.id]: action.payload },
};
default:
return state;
}
};
// Categories reducer
const categoriesReducer = (state = initialCategoriesState, action) => {
switch (action.type) {
case ADD_CATEGORY:
return {
...state,
categories: {
...state.categories,
[action.payload.id]: action.payload
},
};
default:
return state;
}
};
// Root reducer
const rootReducer = combineReducers({
tasksState: tasksReducer,
categoriesState: categoriesReducer,
});
// Create store
const store = createStore(rootReducer);
export default store;
JavaScript
// App.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addTask } from './store';
import './App.css'
// TaskForm Component
const TaskForm = () => {
const dispatch = useDispatch();
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const task = {
id: Math.random().toString(36).substr(2, 9),
name: formData.get('name'),
categoryId: formData.get('category'),
};
dispatch(addTask(task));
e.target.reset();
};
return (
<form onSubmit={handleSubmit}>
<input type="text" name="name" placeholder="Task Name" required />
<select name="category" required>
{[1, 2, 3].map((categoryId) => (
<option key={categoryId} value={categoryId}>Category {categoryId}</option>
))}
</select>
<button type="submit">Add Task</button>
</form>
);
};
// TaskList Component
const TaskList = ({ categoryId }) => {
const tasks = useSelector((state) => {
return Object.values(state.tasksState.tasks).filter(task => task.categoryId == categoryId);
});
return (
<div>
<h3>Category {categoryId} Tasks</h3>
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.name}</li>
))}
</ul>
</div>
);
};
// App Component
const App = () => (
<div>
<img src='https://media.geeksforgeeks.org/gfg-gg-logo.svg' alt='gfg_logo' />
<TaskForm />
{[1, 2, 3].map(categoryId => (
<TaskList key={categoryId} categoryId={categoryId} />
))}
</div>
);
export default App;
JavaScript
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Output:
Split Reducer Output
Using Reselect Library
The reselect library in React-Redux creates memoized selectors to efficiently compute state data, ensuring components re-render only when relevant state changes.
Example: Below is an example to optimize the performance of React-Redux applications using Reselect Library.
CSS
/* App.css */
button {
background-color: rgb(228, 233, 224);
border: 1px solid transparent;
cursor: pointer;
padding: 10px 20px;
margin: 10px;
}
button:hover {
background-color: rgb(77, 197, 77);
}
input,
select {
padding: 10px 20px;
margin: 5px;
}
#App{
display: flex;
flex-direction: column;
align-items: center;
}
JavaScript
// store.js
import { createStore, combineReducers } from 'redux';
import { createSelector } from 'reselect';
// Action Types
const ADD_USER = 'ADD_USER';
const ADD_ACTIVITY = 'ADD_ACTIVITY';
// Action Creators
export const addUser = (user) => ({ type: ADD_USER, payload: user });
export const addActivity = (activity) => ({ type: ADD_ACTIVITY, payload: activity });
// Reducers
const usersReducer = (state = [], action) => {
switch (action.type) {
case ADD_USER:
return [...state, action.payload];
default:
return state;
}
};
const activitiesReducer = (state = [], action) => {
switch (action.type) {
case ADD_ACTIVITY:
return [...state, action.payload];
default:
return state;
}
};
const rootReducer = combineReducers({
users: usersReducer,
activities: activitiesReducer,
});
// Selectors
const getUsers = (state) => state.users;
const getActivities = (state) => state.activities;
export const getUsersWithActivities = createSelector(
[getUsers, getActivities],
(users, activities) =>
users.map((user) => ({
...user,
activities: activities.filter((activity) => activity.userId === user.id),
}))
);
const store = createStore(rootReducer);
export default store
JavaScript
// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addUser, addActivity, getUsersWithActivities } from './store';
import './App.css'
let userCount = 0, activityCount = 0;
const App = () => {
const dispatch = useDispatch();
const usersWithActivities = useSelector(getUsersWithActivities);
const handleAddUser = () => {
const newUser = { id: Date.now(), name: `User ${++userCount}` };
dispatch(addUser(newUser));
};
const handleAddActivity = (userId) => {
const newActivity = { id: Date.now(), userId, description: `Activity ${++activityCount}` };
dispatch(addActivity(newActivity));
};
return (
<div id='App'>
<div style={{ display: 'flex', alignItems: 'center' }}>
<img src='https://media.geeksforgeeks.org/gfg-gg-logo.svg' alt='gfg_logo' /> {" "}
<button onClick={handleAddUser}>Add User</button>
</div>
<ul>
{usersWithActivities.map((user) => (
<li key={user.id}>
{user.name}
<button onClick={() => handleAddActivity(user.id)}>Add Activity</button>
<ul>
{user.activities.map((activity) => (
<li key={activity.id}>{activity.description}</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
};
export default App;
JavaScript
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Output:
Reselect Library Output
Similar Reads
How can you optimize the performance of React-Redux applications?
Performance optimization in React-Redux involves improving the speed, efficiency, and responsiveness of applications by minimizing rendering times, reducing unnecessary re-renders, and optimizing data fetching and processing. By implementing optimization techniques, you can enhance the overall user
5 min read
How to optimize the performance of React app ?
The operations involved in keeping the DOM updates are costly but react uses several techniques to minimize the no. of operations which leads to natively faster UI for many cases. The following techniques can be used to speed up the application: Table of Content Use binding functions in constructors
3 min read
What Are Some Common Performance Bottlenecks in React-Redux Applications?
React-Redux applications are powerful for building complex and scalable web applications. However, as applications grow in size and complexity, performance optimization becomes important to ensure smooth user experiences. Identifying and addressing common performance bottlenecks is key to maintainin
3 min read
How to test React-Redux applications?
Testing React-Redux applications is crucial to ensure their functionality, reliability, and maintainability. As we know, the React-Redux application involves complex interactions between components and Redux state management, testing helps us to identify and prevent bugs, regressions, and performanc
10 min read
How to Normalize State in Redux Applications ?
In Redux applications, efficient state management is essential for scalability and maintainability. Normalization is a technique used to restructure complex state data into a more organized format, improving performance and simplifying state manipulation. This article covers the concept of normaliza
3 min read
How to Implement Caching in React Redux applications ?
Caching is the practice of storing frequently used or calculated data temporarily in memory or disk. Its main purpose is to speed up access and retrieval by minimizing the need to repeatedly fetch or compute the same information. By doing so, caching helps reduce latency, conserve resources, and ult
3 min read
How to improve slow React application rendering ?
Slow React application rendering as its name suggests is a small or large delay in rendering elements. There may be multiple reasons for that. React uses the concept of Virtual DOM. All the elements in React are rendered using the render method in which we have to provide an id of an element (mostly
4 min read
How to implement pagination in React Redux Applications?
Pagination is a common requirement in web applications. It is very helpful when we wish to display or manage a large dataset on the website in an aesthetic manner. Whenever it comes to displaying a large number of data, state handling comes into the picture. The idea of pagination has a good binding
5 min read
How useMemo Hook optimizes performance in React Component ?
The useMemo hook in React optimizes performance by memoizing the result of a function and caching it. This caching ensures that expensive computations inside the useMemo callback are only re-executed when the dependencies change, preventing unnecessary recalculations and improving the rendering perf
2 min read
How to Handle Errors in React Redux applications?
To handle errors in Redux applications, use try-catch blocks in your asynchronous action creators to catch errors from API calls or other async operations. Dispatch actions to update the Redux state with error information, which can then be displayed to the user in the UI using components like error
4 min read