Redux Middleware: A Perfect Beginner’s Guide

Redux Middleware: What struck your mind when you first heard the term ‘Middleware’? Let’s first try to understand it with the most general definition:-

Middleware offers a means for communicating with the action being dispatched before they reach the reducer.

Before understanding Redux Middleware, you should have a clear concept of redux. So let’s have a brief introduction about redux.


Redux is an open-source JavaScript library for front-end development. It’s an application data flow architecture. It is used with React to solve the ‘state transfer problem.’ It maintains a single immutable store tree to keep the state of the whole application which can’t be changed directly. A new object of the state is created when something changes (using actions and reducers). Redux has become popular because of its simplicity and small size(2 KB).

Redux Middleware

Redux middleware acts as a medium between dispatching an action and handing over the action to the reducer. It listens to all dispatches and executes code with the details of the actions and the current states. It is possible to combine multiple middlewares to add new features, and each middleware does not require an understanding of what happened before and after.

Action -> Middleware -> Reducer

Examples of middleware include, handle asynchronous requests(like HTTP call to the server), logging, routing, etc.

Middlewares are mainly used to handle asynchronous actions in your application. Redux’s popular middleware libraries that allow for side effects and asynchronous actions are Redux-thunk and Redux-Saga.

Redux thunk

Redux thunk is the most popular middleware that allows you to call action creators, which then returns a function instead of an action object. This function receives the store’s dispatch method, which is then used to dispatch the regular synchronous actions within the function’s body once the asynchronous operations have been completed. It is a programming concept where the function(thunk) is used to delay the evaluation of the operation or process. It is used for communicating asynchronously with an external API(Application Programming Interface) to fetch or save data.

Let’s see how you can include Redux-thunk in your application.

$ yarn add redux-thunk

Or using npm:

$ npm install redux-thunk

Let’s try to understand how ‘thunk’ actually works by implementing a small example of fetching the details of a particular user by hitting an API.

// Index.js
import React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import * as serviceWorker from './serviceWorker';import userDataReducer from './Reducer/reducer';import {Provider} from 'react-redux';import {createStore, applyMiddleware} from 'redux';import thunk from 'redux-thunk';
const store= createStore(userDataReducer, applyMiddleware(thunk))ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

// Api

Here you can hit the API and return the response back to the calling function.

import axios from 'axios';const reposApi = {   getUserDetails: () => {       let url = 'https://users/getUserData/1';       return axios.get(url);   }}export default reposApi;

// Action creator

It returns a function that calls an API, which further returns a promise. Once it has been resolved, it dispatches an action again, which is then matched to the corresponding action-type and eventually reaches the reducer.

import * as actionType from './actionType';import reposApi from '../Api/repos';export function getUserDetails(){return (dispatch) => {reposApi.getUserDetails().then(response => {dispatch(getUserDetailsAction(response));}).catch(err => {console.log("error occurred ====>>>", err);})}}export const getUserDetailsAction = item => {   return {       type: actionType.GET_PROFILE,       payload: item   }}

// Reducer

Reducer updates the state object after performing the required calculation.

import * as actionType from "../Action/actionType";
const initialState = {profile: {}};
const userDataReducer = (state = initialState, action) => { switch (action.type) {
case actionType.GET_PROFILE: return { ...state, profile: };default: return state;}export default userDataReducer;

Let’s move on to the next Redux middleware.

Redux Saga

Like Redux-Thunk, Redux-Saga is a middleware library used to handle side effects and asynchronous action calls in a redux app in an effective way. It achieves this by using the generator function. Generator functions are not like the actual functions which we know, but rather it is a special type of function which has the ability to pause in the middle of the execution and resume later. Not only this, but you can also do this as many times as you want. Inside the generator function, there is a keyword ‘yield’, which is used to pause the execution. It is favored over thunk, because of easy testability.

Here is the syntax of a generator function:-

function *function_name{yield “Hi, I am generator”;}

Let’s try to understand Redux-Saga by implementing a small example in which we will hit an API to fetch the user.

// Action Creators

const requestUser = () => {   return { type: 'REQUESTED_USER' } };  const requestUserSuccess = (data) => {   return { type: 'REQUESTED_USER_SUCCESS', url: data.message } };  const requestUserError = () => {   return { type: 'REQUESTED_USER_FAILURE' } };  const fetchUser = () => {   return { type: 'FETCHED_USER' } };

// Sagas

function* watchFetchUser() {   yield takeEvery('FETCHED_USER', fetchUserAsync); }  function* fetchUserAsync() {   try {     yield put(requestUser());     const data = yield call(() => {       return fetch('https://getData/userDetails/user')               .then(res => res.json())       }     );     yield put(requestUserSuccess(data));   } catch (error) {     yield put(requestUserError());   } }

// Reducer

const initialState = {   url: '',   error: false };  const reducer = (state = initialState, action) => {   switch (action.type) {     case 'REQUESTED_USER':       return {         url: '',         error: false       };     case 'REQUESTED_USER_SUCCESS':       return {         url: action.url,         error: false       };     case 'REQUESTED_USER_FAILURE':       return {         url: '',         error: true       };     default:       return state;   } };

// Store

const sagaMiddleware = createSagaMiddleware();const store = createStore( reducer, applyMiddleware(sagaMiddleware));;


The component first dispatches the action FETCHED_USER. Then, the watcher saga (watchFetchUser) takes the dispatched action and calls the worker saga (fetchUserAsync), followed by the execution of the API call. At last, an action to update the state is dispatched (success or failure).

My self sasi working in Cronj Tecchnologies