Middleware in Redux

Middleware is a "middle-man" between your store running actions and reducers changing the state. You can have more than 1 middleware in your project.

It can be used when to log whenever an action has occurred or even give crash reports. Middleware is declared in your ./src/index.js file.

applyMiddleware needs to be imported from redux.

import { createStore, applyMiddleware } from 'redux';

This next snippet is from the Redux docs since it's a good example. This needs to be declared before creating the store.

const logger = store => {
  return next => {
    return action => {
      console.log('dispatching', action);
      const result = next(action);
      console.log('new state', store.getState());
      return result;
    }
  }
}

There are a few things going on here:

  • store is the created store being used
  • logs to the console what action is being dispatched
  • next(action) is the same as store.dispatch(action), which is dispatching the given action
  • store.getState() returns the current state of the store and logs it to the console

applyMiddleware() passes logger as an argument and is the second argument in the createStore() method.

In my Redux post , the Redux Devtools was declared as the second argument, this will be changed soon.

const store = createStore(
    reducer,
    applyMiddleware(logger)
);

The image below shows the 2 console messages.

Console example from logger middleware Console example from logger middleware

There are some pre-made middlewares you can use such as redux-thunk which is made for using asynchronous actions in your store.

Install:

npm install redux-thunk

Import thunk from redux-thunk in ./src/index.js:

import thunk from 'redux-thunk';

Then add it to the applyMiddleware() method.

const store = createStore(
  reducer,
  applyMiddleware(logger, thunk)
);

In colors.js where the actions are declared, I renamed removeColor to removeColorAction and kept the same logic. Instead of a component removing a color immediately, a new created removeColorDelay will be used to dispatch this action. Because of redux-thunk, I can create a setTimeout to make an asynchronous dispatch.

./src/store/actions/colors.js

const removeColorAction = (color) => {
    return {
        type: actionTypes.REMOVE_COLOR,
        color: color
    }
}

export const removeColorDelay = (color) => {
    // dispatch is from redux-thunk
    return dispatch => {
        setTimeout(() => {
            dispatch(removeColorAction(color));
        }, 3000)
    }
}

With a component calling removeColorDelay, there will be a 3 sec delay before the color is removed from the state.

If using the Redux Devtools , you need to change the setup when using middleware.

Import compose from redux.

import { createStore, applyMiddleware, compose } from 'redux';

Declare a composeEnhancers constant which wraps the applyMiddleware() function.

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  reducer,
  composeEnhancers(applyMiddleware(logger, thunk))
);

This example can be found in the redux-intro repo .

Resources: