FAQ: Redux Middleware - Write Your Own Middleware

This community-built FAQ covers the “Write Your Own Middleware” exercise from the lesson “Redux Middleware”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Redux

FAQs on the exercise Write Your Own Middleware

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!
You can also find further discussion and get answers to your questions over in Language Help.

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head to Language Help and Tips and Resources. If you are wanting feedback or inspiration for a project, check out Projects.

Looking for motivation to keep learning? Join our wider discussions in Community

Learn more about how to use this guide.

Found a bug? Report it online, or post in Bug Reporting

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

Does anyone else find it confusing that Codecademy hops around between redux libraries (redux, react-redux, reduxToolKit)?

It doesnt seem clear at this point whether these libraries are 100% mutually exclusive or can be used together in some ways?

It appeared as though Redux ToolKit was the most effective way to configure the store, yet in this exercise we revert back to regular redux to implement the middleware.

11 Likes

Would like a simple explanaition on the syntax of arrow function(s?) here.
Is it like three nested functions?

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

Could it be writen like this?

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

You forgot the return keyword in your longform.
This

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

Can be written like this:

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

Why does the middleware signature use currying?

Redux middleware are written using a triply-nested function structure that looks like const middleware = storeAPI => next => action => {} , rather than a single function that looks like const middleware = (storeAPI, next, action) => {} . There’s a few reasons for this.

One is that “currying” functions is a standard functional programming technique, and Redux was explicitly intended to use functional programming principles in its design. Another is that currying functions creates closures where you can declare variables that exist for the lifetime of the middleware (which could be considered a functional equivalent to instance variables that exist for the lifetime of a class instance). Finally, it’s simply the approach that was chosen when Redux was initially designed.

The curried function signature of declaring middleware is deemed unnecessary by some, because both store and next are available when the applyMiddleware function is executed. This issue has been determined to not be worth introducing breaking changes, as there are now hundreds of middleware in the Redux ecosystem that rely on the existing middleware definition.

3 Likes

if the higher order functional syntax confuses you. please read the chapter on HOF from the linked book in the lesson.

2 Likes

Okay I don’t get it. It says in step 5 that new state should be logged to console
image

BUT all I get is the action that was dispatched to the state
image

Is that a mistake in instructions or something is wrong?

NOTE: This screenshots were taken with Solution provided to exercise, it still shows only action, not the state,
however if I do

console.log(store.getState())
after the action was dispatched it show correct state
image

1 Like

Okay for everyone confused like me, here it is:

It should be
image
or better storeAPI.getState(), since we’re using storeAPI in our logger

not the like in the instructions and solution
image
to get the state logged to console,

you can follow this page from Redux Docs

2 Likes

Hi there, I find it confusing in this modul “Write Your Own Middleware” that console.log(StoreAPI.getState()) has not been logged but instead visually hided. What is it and why is it? CODE Snippet might not work but when you do it in your own workspace it does.

import { createStore, applyMiddleware } from 'redux'; const messageReducer = (state = '', action) => { if (action.type === 'NEW_MESSAGE') { return action.payload; } else { return state; } } // Paste the logger function here. const logger = storeAPI => next => action => { // do stuff here console.log(storeAPI.getState()); console.log("Gap created") console.log(storeAPI.getState()); const nextState = next(action); console.log(storeAPI.getState()); console.log(nextState) console.log(storeAPI.getState()); return nextState; }; const store = createStore(messageReducer, '', applyMiddleware(logger)); store.dispatch({ type: 'NEW_MESSAGE', payload: 'I WROTE A MIDDLEWARE' })

You get a blank line when you log the storeAPI.getState() because the state is a blank space ' '. You can see the second parameter in the call to createStore(messageReducer, '', applyMiddleware(logger)); that you set the initialState to a blank space.

I got the same problem as you, and I thought that I was the only one who saw their mistake.
But now I have another question. Why do we have to return the nextState variable even after we called next(action)?

I see that the program works very well even if we comment the last line with the return statement, because we passed the action to the next middleware in the pipeline.

2 Likes

Does anyone notice that earlier it was taught that createStore() can have only one parameter, i.e, root reducer. then how in this lesson we are passing three arguments. Does anyone know, where am I mistaken?

In your solution, you are not returning the new state, but the action. Same as in the, IMHO, buggy excersise, which is not the functionality expected from this logger function.
I refactor the code to actually achieve what this looger function is supposed to do. Please check the comments inline:

import { createStore, applyMiddleware } from 'redux';//createStore is deprecated. configureStore must be used instead according to Redux Toolkit. But we will keep it like this to stay true to the outdated example provided


const messageReducer = (state = 'Default State', action) => {// In order for the first storeAPI.getState() log something more than an empty line (counfusing), defalut state is set to the string 'Default state'. The redundant default state empty string in createStore a few lines after has been removed too.
  if (action.type === 'NEW_MESSAGE') {
    return action.payload;
  } else {
    return state;
  }
}

// Paste the logger function here > CALLING THIS "THE MIDDLEWARE LOGGER FUNCTION" WOULD HAVE MAKE EVERYTHING MORE CLEAR
const logger = storeAPI => next => action => {
  console.log(storeAPI.getState())// This will log the default state
  next(action);//dispatches action type:'NEW_MESSAGE', updating state, since this is the last (and only) reducer in the pipeline
  const nextState = (store.getState())// saves the updated state to a variable that we can log and return. Not actually needed, but I guess is an abstraction to make the code easier to read. this could have been ommited and then, in the return statement, return storeAPI.getState()
  console.log(nextState)// Logs current state. Same as before: could have been written console.log(storeAPI.getState())
  return nextState;// returns the new update state. Could have been written return storeAPI.getState(). I DON'T UNDERSTAND WHY THIS MIDDLEWARE HAS TO RETURN ANYTHING. IF THERE WERE A NEXT MIDDLEWARE IN THE PIPELINE, IT WOULDN'T SEEM TO BE ABLE TO USE IT.
};
const store = createStore(messageReducer, applyMiddleware(logger));// Default state (second argument) removed. This was not explained before, nor needed in this exercise

store.dispatch({type: 'NEW_MESSAGE', payload: 'I WROTE A MIDDLEWARE'})

createStore() can take three parametes. You can check this in the documentation:

  • Reducers
  • [PreloadedState]
  • [enhancers]

Anyway, createStore() is deprecated. It works but the current recommended way is using configureStore from @redux/toolkit.

Check my code example respone here in this same thread.

Two years later and still the same issue smh