Creating custom middlewares in React Redux
Last Updated :
23 Jul, 2025
In React-Redux applications, managing the flow of data is crucial for building efficient and scalable apps. Redux provides a powerful state management solution, and custom middleware adds an extra layer of flexibility to handle complex scenarios effectively.
Let's understand custom middleware in simpler terms and see how we can create and use them.
What is Middleware?
When you dispatch an action in your application, it goes through a series of checkpoints before reaching the reducers. These checkpoints are the middleware. They intercept actions, perform specific tasks, and then pass them along to the next middleware or finally to the reducers. Middlewares in React Redux act as a bridge between actions being dispatched and reducers that update the state accordingly. They intercept actions before they reach reducers, allowing for additional functionality such as logging, asynchronous operations, or dispatching multiple actions based on a single action.
Creating Custom Middleware:
To create a custom middleware, you define a function that follows a particular pattern. This function receives the Redux store as its first parameter and returns another function. This returned function then takes next
as its parameter, which represents the next middleware in the chain. Inside this function, you'll handle your custom logic and eventually call next(
action
)
to pass the action forward.
Step 1: Middleware Structure First, let's define the structure of our middleware function. A middleware in Redux is a function that returns another function, which takes store
as its argument. This function then returns another function that takes next
as its argument, representing the next middleware in the chain.
const customMiddleware = store => next => action => {
// Middleware logic goes here
}
Step 2: Implement Middleware Logic Inside our middleware function, we can implement the desired logic. For example, let's create a simple logger middleware that logs each dispatched action to the console along with the current state.
const loggerMiddleware = store => next => action => {
console.log('Dispatching action:', action);
console.log('Current state:', store.getState());
next(action);
}
Step 3: Apply Middleware to Redux Store to apply our custom middleware to the Redux store, we use the applyMiddleware
function provided by Redux.
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(loggerMiddleware));
Practical Use Cases:
Custom middlewares can be used for various purposes in React Redux applications. Some common use cases include:
- Authentication: Middleware can intercept actions related to user authentication, validate tokens, and handle authentication flows.
- Logging: As demonstrated above, middleware can log actions, state changes, or any other relevant information for debugging purposes.
- Asynchronous Operations: Middleware can handle asynchronous actions such as making API requests, dispatching multiple actions based on the result, or handling errors.
- Caching: Middleware can implement caching mechanisms to optimize performance by storing frequently accessed data locally.
Example: Below are the example to create custom middleware in React Redux.
- Install the necessary package in your application using the following command.
npm install react-redux redux
JavaScript
// App.js
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { fetchUsersRequest }
from './actions/userAction';
const App = ({ users, loading, error, fetchUsers }) => {
useEffect(() => {
fetchUsers();
}, [fetchUsers]);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
if (!users || users.length === 0) {
return <div>No users found</div>;
}
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => {
return (
<li key={user.id}>{user.name}</li>
);
})}
</ul>
</div>
);
};
const mapStateToProps = state => {
return {
users: state.users || [],
loading: state.loading,
error: state.error
};
};
const mapDispatchToProps = dispatch => ({
fetchUsers: () => dispatch(fetchUsersRequest())
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
JavaScript
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
const root = createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
JavaScript
// store.js
import { applyMiddleware, createStore } from 'redux';
import userReducer from './reducers/userReducer';
import apiMiddleware from './middleware/apiMiddleware';
const store = createStore(
userReducer,
applyMiddleware(apiMiddleware)
);
export default store;
JavaScript
// src/middleware/apiMiddleware.js
const apiMiddleware = store => next => action => {
if (action.type === 'FETCH_USERS_REQUEST') {
// Dispatch a loading action
store.dispatch({ type: 'FETCH_USERS_LOADING' });
setTimeout(() => {
const users = [
{ id: 1, name: 'Rahul' },
{ id: 2, name: 'Sandeep' },
{ id: 3, name: 'Summit' },
{ id: 4, name: 'Riya' },
{ id: 5, name: 'Eva' }
];
store.dispatch({
type: 'FETCH_USERS_SUCCESS',
payload: users
});
}, 1000);
}
return next(action);
};
export default apiMiddleware;
JavaScript
// src/actions/userActions.js
export const fetchUsersRequest = () => ({
type: 'FETCH_USERS_REQUEST'
});
export const fetchUsersSuccess = users => ({
type: 'FETCH_USERS_SUCCESS',
payload: users
});
export const fetchUsersFailure = error => ({
type: 'FETCH_USERS_FAILURE',
payload: error
});
JavaScript
// src/reducers/userReducer.js
const initialState = {
users: [],
loading: false,
error: null
};
const userReducer = (state = initialState, action) => {
switch (action.type) {
case 'FETCH_USERS_REQUEST':
return { ...state, loading: true };
case 'FETCH_USERS_SUCCESS':
return {
...state, loading: false,
users: action.payload, error: null
};
case 'FETCH_USERS_FAILURE':
return {
...state, loading: false,
error: action.payload
};
default:
return state;
}
};
export default userReducer;
Start your application using the following command.
npm start
Output:
Output
Similar Reads
React Tutorial React is a powerful JavaScript library for building fast, scalable front-end applications. Created by Facebook, it's known for its component-based structure, single-page applications (SPAs), and virtual DOM,enabling efficient UI updates and a seamless user experience.Note: The latest stable version
7 min read
React Fundamentals
React IntroductionReactJS is a component-based JavaScript library used to build dynamic and interactive user interfaces. It simplifies the creation of single-page applications (SPAs) with a focus on performance and maintainability. "Hello, World!" Program in ReactJavaScriptimport React from 'react'; function App() {
6 min read
React Environment SetupTo run any React application, we need to first setup a ReactJS Development Environment. In this article, we will show you a step-by-step guide to installing and configuring a working React development environment.Pre-requisite:We must have Nodejs installed on our PC. So, the very first step will be
3 min read
React JS ReactDOMReactDOM is a core React package that provides DOM-specific methods to interact with and manipulate the Document Object Model (DOM), enabling efficient rendering and management of web page elements. ReactDOM is used for: Rendering Components: Displays React components in the DOM.DOM Manipulation: Al
2 min read
React JSXJSX stands for JavaScript XML, and it is a special syntax used in React to simplify building user interfaces. JSX allows you to write HTML-like code directly inside JavaScript, enabling you to create UI components more efficiently. Although JSX looks like regular HTML, itâs actually a syntax extensi
5 min read
ReactJS Rendering ElementsIn this article we will learn about rendering elements in ReactJS, updating the rendered elements and will also discuss about how efficiently the elements are rendered.What are React Elements?React elements are the smallest building blocks of a React application. They are different from DOM elements
3 min read
React ListsIn lists, React makes it easier to render multiple elements dynamically from arrays or objects, ensuring efficient and reusable code. Since nearly 85% of React projects involve displaying data collectionsâlike user profiles, product catalogs, or tasksâunderstanding how to work with lists.To render a
4 min read
React FormsIn React, forms are used to take input from users, like text, numbers, or selections. They work just like HTML forms but are often controlled by React state so you can easily track and update the input values.Example:JavaScriptimport React, { useState } from 'react'; function MyForm() { const [name,
4 min read
ReactJS KeysA key serves as a unique identifier in React, helping to track which items in a list have changed, been updated, or removed. It is particularly useful when dynamically creating components or when users modify the list. When rendering a list, you need to assign a unique key prop to each element in th
4 min read
Components in React
React Lifecycle In React, the lifecycle refers to the various stages a component goes through. These stages allow developers to run specific code at key moments, such as when the component is created, updated, or removed. By understanding the React lifecycle, you can better manage resources, side effects, and perfo
7 min read
React Hooks
Routing in React
Advanced React Concepts
React Projects