Learn

Before we get to redux-thunk specifically, we want to solidify our understanding of how middleware fits into Redux’s data flow. Let’s explore how middleware actually gets invoked in Redux, so that we know how a middleware should be structured. After that, we’re going to write a simple middleware from scratch.

But first, you’ll recall from the previous exercise that middleware runs after an action is dispatched and before that action is passed along to the reducer. How does this actually work?

To add a middleware to our project, we use Redux’s applyMiddleware function like so.

import { createStore, applyMiddleware } from 'redux'; import { middleware1, middleware2, middleware3 } from './exampleMiddlewares'; import { exampleReducer } from './exampleReducer'; import { initialState} from './initialState'; const store = createStore( exampleReducer, initialState, applyMiddleware( middleware1, middleware2, middleware3 ) );

The specifics of how applyMiddleware works are outside the scope of this lesson. All you need to know is that once middleware has been added to a Redux project, calls to dispatch are actually calls to the middleware pipeline (the chain of all added middlewares). This means that any actions we dispatch will be passed from middleware to middleware before they hit an app’s reducers.

Middlewares must conform to a specific, nested function structure in order to work as part of the pipeline (this nested structure is also called a higher-order function, if you’d like to read more). That structure looks like this:

const exampleMiddleware = storeAPI => next => action => { // do stuff here return next(action); // pass the action on to the next middleware in the pipeline }

Each middleware has access to the storeAPI (which consists of the dispatch and getState functions), as well as the next middleware in the pipeline, and the action that is to be dispatched. The body of the middleware function performs the middleware’s specific task before calling the next middleware in the pipeline with the current action (note that if the middleware is the last in the pipeline, then next is storeAPI.dispatch so calling next(action) is the same as dispatching the action to the store).

Now let’s write a custom middleware that logs the contents of our store to the console.

Instructions

1.

In the code editor, you’ll notice we’ve created a simple reducer for you, and taken care of importing Redux’s createStore and applyMiddleware functions. We’ve created a store by calling createStore and passing it the reducer. Since all Redux middleware have the same basic structure, you can start by copying this snippet:

const logger = storeAPI => next => action => { // do stuff here return next(action); };
2.

Replace the comment // do stuff here, with a line of code that logs the contents of the store to the console. Remember, you can access the store’s state with storeAPI.getState().

3.

Instead of returning next(action), store the result of that function call in a const called nextState. Next, log nextState to the console. Finally, return nextState.

4.

Apply your custom middleware to your store by adding a third argument to the call to createStore. This argument should be the result of calling applyMiddleware with the logger middleware you’ve written.

5.

Dispatch the following action to your store:

{ type: 'NEW_MESSAGE', payload: 'I WROTE A MIDDLEWARE' }

Note that the store’s new state was logged to the console. Congrats – you just wrote your first middleware!

Take this course for free

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?