Before we dive into running asynchronous code, let me dive into a super important advanced concept we
have when working with redux
and with that, I always mean redux the package on its own, be that connected to your react app or not.
You may add middleware to it right
between your action being dispatched and it reaching the reducer, this is where you can add middleware.
Now you might not know what middleware is, if you're a server side developer having worked with Express.js
for example, you might have an idea though. Middleware basically is a term used for functions or the code
general you hook into a process which then gets executed as part of that process without stopping it.
So we can add middleware and the action will still reach the reducer thereafter but we can do something
with that action before it reaches the reducer, that can be simply logging something,
but that will also become important later when we want to execute asynchronous code,
so for now, let's see middleware in action by adding it to our project. To show you how middleware works,
let me go into the index.js
file, the file where we actually create the store.
It's at this point of time that we can also add middleware to the project and for that of course, we need
to learn how to exactly do that.
First of all we need a middleware.
As I said middleware in this case here is just a piece of code, specifically a function.
Now I'll create my own middleware here,
later we'll add middleware provided by other providers.
I want to create a simple middleware which simply logs each action we issue,
so what I want to do is I'll create a new constant and I'll name it
logger, this will be the name of my middleware so to say, of course the name of the content is totally
up to you as always. This then takes a function
and I will use the ES6 arrow syntax.
It will get the store as an input, this is the case because we will soon use a specific method provided
by redux to connect our own middleware to the store
and this method provided by redux will eventually execute our middleware function and give us the store.
Now the function body of this middleware function then looks like that, we return another function,
so that can be confusing but this function simply returns another function.
I'll also write this other function in the ES6 arrow function syntax, this
other function will receive the next argument,
you can name this argument whatever you want but next makes sense because this will be a function which
you can execute to let the action continue its journey onto the reducer,
you might know this next function if you are an experienced express developer.
So this function which is returned here will also be executed by redux in the end, this function then
and now it really becomes a bit confusing but this function now also returns a function,
the last one though, which will receive the action you dispatched as an input,
again this function will also be executed for you.
So this nested function party here is simply a middleware,
now inside that inner function which receives the action, we can also access a store and this next function
and of course the action itself.
And here we can now execute the code we want to run in between the action and the reducer.
So here I'll add a log statement, mark it as middleware,
so that's just for us so that we can quickly see where this is coming from
and there I'll say dispatching and I'll print the action. Thereafter, I will execute next
and here, important,
this will now let the action continue to the reducer, though for that to succeed, we need to pass the action
as an argument,
now that's important because you could theoretically also change that action here in the middleware,
we have access to it,
we get it as an argument,
we could change the type. Of course we should do that with caution because we can break our application
or worse than that,
we can implement unexpected behaviors.
So here I will call next and pass the unmodified action,
the cool thing is I can now store the result of this call which I will need to return in this inner function,
so I will return results here.
Now in between these two steps, I can log something else,
so console log, log a middleware related log statement here and there,
I will have my next state so I can simply called store.getState because I do have access to my store,
we get it in the outer function,
it's the normal redux store which you learn has to getState method,
so I can of course call that in the middleware too.
So this function tree is in the end what gets executed,
all of that is done by redux, we don't have to call any of these functions,
all we have to do is apply this middleware to our store.
So how do we do that?
First of all, we need to import something from redux,
so here besides combineReducers, I'll import applyMiddleware, this function as the names suggests
allows us to add our own middleware to the store.
So here in create store where we initialize the store,
we can add more arguments
and the second argument here can be a so-called enhancer.
Now this enhancer is nothing else than a middleware for example,
so here we can call applyMiddleware and now we can pass our logger constant which holds this function
tree which happens to be a valid middleware executable by redux to apply middleware and therefore connect
that to the store.
And this already is all here
and actually, you can pass a list of middlewares here to applyMiddleware,
they will be executed in order then. Here we only have one though,
so let's save this and then run npm start to start this project.
This should allow us to still use the project as before but we should get additional output here on
the right in the console.
So here if we click increment, we see two logs here,
the first one is the dispatching log where we see the action we dispatched,
that's the javascript object we dispatched
and the second one is the next state where we see the updated state and that of course happens for every
action we dispatch.
So this is our middleware in action,
now of course the middleware can already be nice to do exactly that, log your state and see very
well what's going on. Now
a more useful use case for a middleware is to be seen later when we actually handle asynchronous code.
But first I want to stick to this idea of getting some insights into this state,
it would be nice for debugging if we could always look into the store.
So if we had some logging but more than that, that even if we just didn't dispatch anything, we could
still look into the current store.
Let's have a look at what can help us with that in the next lecture.