The Secret Sauce of Redux: Exploring the World of Middleware

The Secret Sauce of Redux: Exploring the World of Middleware

What are middlewares?

In Redux, middleware is a piece of code that sits between the actions that are dispatched to the store and the reducers that update the state based on those actions.

Middleware allows you to intercept and modify actions before they reach the reducers, or to perform additional tasks such as logging, asynchronous API calls, or handling side effects.

When you dispatch an action, it flows through the middleware chain before it reaches the reducers. Each middleware can intercept the action, modify it, or even dispatch additional actions.

For example, you could use middleware to make an API call to retrieve data from a server and dispatch a new action with the results once the data has been retrieved. This allows you to separate the concerns of data fetching and state management.

Some popular middleware libraries for Redux include Redux Thunk, Redux-Saga, and Redux Observable. These libraries provide additional functionality for handling asynchronous actions and side effects.

How to make custom middleware?

Redux middlewares are implemented using currying in JavaScript. Currying is a technique where a function with multiple arguments is transformed into a sequence of functions that each take a single argument. This can be useful in functional programming because it allows for more flexibility and composability in function composition.

function add(x) {
  return function(y) {
    return x + y;
  }
}

// Now we can create new functions by partially applying `add`
const add5 = add(5);
const add10 = add(10);

console.log(add5(3)); // Output: 8
console.log(add10(7)); // Output: 17

Middleware is a curry function that takes a reference to the store object and returns another function that takes a reference to the next middleware in the chain, and finally returns a function that handles the action.

const myMiddleware = (store) => (next) => (action) => {
  // Do something with the action before it reaches the reducers
  console.log(`Action ${action.type} dispatched with payload: ${action.payload}`);

  // Call the next middleware in the chain or the store's dispatch method
  const result = next(action);

  // Do something with the result after the action has been handled by the reducers
  console.log(`State after ${action.type} action: ${JSON.stringify(store.getState())}`);

  // Return the result from the next middleware or the store's dispatch method
  return result;
};

It is mandatory to return next(action). If you don't return the next(action) at the end of a middleware function in Redux, the action will not be passed on to the next middleware in the chain. This means that any subsequent middleware functions or reducers will not be able to handle the action.

How to use middlewares in redux store?

We have created a custom middleware, and now users need to use it in our redux store. To use middleware in a Redux store, you can pass it as an argument to the applyMiddleware() function when creating the store using createStore().

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import loggerMiddleware from 'redux-logger';
import rootReducer from './reducers';

// Create an array of middleware functions to use
const middlewares = [thunkMiddleware, loggerMiddleware];

// Create the store with the middleware
const store = createStore(rootReducer, applyMiddleware(...middlewares));

// Use the store in your application