Async Operation in Redux
Redux Async Data Flow
How data flows in async operation
An event is fired (user clicks a button)
The event handler calls the
dispatch()functionThe
dispatch()function sends the action or thunk (function) to thereducer()functionThe middleware intercept the action or thunk so that the action or thunk can't reach the
reducer()function directlyThe middleware does some work (e.g. fetch data from api)
Our action dispatches and the reducer returns a new state with updated value
The new state is passed to the UI which reflects the changes.



Handling Async operation in Redux using Middleware 
Redux app that uses middleware to fetch data from api and store them in the state.
const { createStore, legacy_createStore, applyMiddleware } = require("redux");
const { delayActionMiddleware, fetchDataMiddleware } = require("./middlewares");
// initial state
const initialState = {
  todos: [],
};
// creating reducers
const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case "added":
      return {
        ...state,
        todos: [
          ...state.todos,
          {
            title: action.payload,
          },
        ],
      };
    case "loaded":
      return {
        ...state,
        todos: [...state.todos, ...action.payload],
      };
    default:
      break;
  }
};
// creating store
const store = legacy_createStore(
  todoReducer,
  applyMiddleware(delayActionMiddleware, fetchDataMiddleware)
);
// subscription
store.subscribe(() => {
  console.log(store.getState());
});
// dispatch actions
store.dispatch({
  type: "added",
  payload: "Learn NodeJs",
});
store.dispatch({
  type: "fetchData",
});const fetch = require("node-fetch");
// Define the delayActionMiddleware as a function that takes the Redux store as a parameter
const delayActionMiddleware =
  (store) =>
  // Return another function, which is the actual middleware that Redux will invoke
  (next) =>
  // This function takes the next parameter, which represents the next middleware or the final dispatch function
  (action) => {
    // Check if the action type is "added"
    if (action.type === "added") {
      console.log("Delay....."); // Log a message indicating the delay
      // Set up a timeout using setTimeout to delay the execution of the next(action) call
      setTimeout(() => {
        next(action); // Invoke the next function with the delayed action
      }, 4000);
      return; // Exit the middleware function
    }
    // If the action type is not "added," immediately call the next function with the action
    return next(action);
  };
// Define the delayActionMiddleware as a function that takes the Redux store as a parameter
const fetchDataMiddleware =
  (store) =>
  // Return another function, which is the actual middleware that Redux will invoke
  (next) =>
  // This function takes the next parameter, which represents the next middleware or the final dispatch function
  async (action) => {
    // Check if the action type is "fetchData"
    if (action.type === "fetchData") {
      const res = await fetch(
        "https://jsonplaceholder.typicode.com/todos?_limit=5" // fetch data from api
      );
      const data = await res.json(); // store data
      // dispatch action to reducer
      store.dispatch({
        type: "loaded",
        payload: data,
      });
      console.log(`Number of updated todos: ${store.getState().todos.length}`);
      return; // Exit the middleware function
    }
    // If the action type is not "loaded," immediately call the next function with the action
    return next(action);
  };
module.exports = {
  delayActionMiddleware,
  fetchDataMiddleware,
};
Last updated
Was this helpful?