在这篇文章中,我们将探讨Redux中的中间件是什么,为什么会用到它,以及如何从头开始创建自己的中间件。
所以,让我们开始吧。
什么是Redux中间件?
Redux中间件允许你拦截发送到还原器的每个动作,这样你就可以对动作进行修改或取消动作。
中间件可以帮助你记录、报告错误、进行异步请求,以及更多。
看一下下面的代码吧:
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
const reducer = (state = 0, action) => {
switch (action.type) {
case "INCREMENT":
return state + action.payload;
case "DECREMENT":
return state - action.payload;
default:
return state;
}
};
const store = createStore(reducer);
store.subscribe(() => {
console.log("current state", store.getState());
});
store.dispatch({
type: "INCREMENT",
payload: 1
});
store.dispatch({
type: "INCREMENT",
payload: 5
});
store.dispatch({
type: "DECREMENT",
payload: 2
});
这里有一个代码沙盒演示。
如果你想逐步了解上面的代码是如何工作的,请查看我的Redux初学者文章。
正如我在那篇文章中解释的,createStore 函数接受三个参数:
- 第一个参数是一个通常被称为还原器的函数--必要参数
- 第二个参数是状态的初始值--可选参数
- 第三个参数是一个中间件--可选参数
如何在React中创建中间件
要创建一个中间件,我们首先需要像这样从Redux导入applyMiddleware 函数:
import { applyMiddleware } from "redux";
假设我们要创建一个loggerMiddleware 。 然后要定义中间件,我们需要使用以下语法:
const loggerMiddleware = (store) => (next) => (action) => {
// your code
};
上面的代码等同于下面的代码:
const loggerMiddleware = function (store) {
return function (next) {
return function (action) {
// your code
};
};
};
一旦中间件函数被创建,我们就像这样把它传递给applyMiddleware 函数:
const middleware = applyMiddleware(loggerMiddleware);
最后,我们将中间件传递给createStore 函数,像这样:
const store = createStore(reducer, middleware);
尽管我们在上面提到,中间件是createStore 函数的第三个参数,第二个参数(初始状态)是可选的。所以根据参数的类型,createStore 函数会自动识别出传递的参数是一个中间件,因为它具有嵌套函数的特定语法。
下面是上述代码的一个更新的代码沙盒演示。
在上面的代码沙盒演示中,loggerMiddleware 看起来是这样的:
const loggerMiddleware = (store) => (next) => (action) => {
console.log("action", action);
next(action);
};
这里是上述代码沙盒演示的预览链接。
如果你检查控制台,你会看到以下输出:

在动作被派发到商店之前,中间件被执行,因为我们可以看到动作被记录到控制台。因为我们在loggerMiddleware 里面通过传递动作来调用next 函数,所以reducer也会被执行,从而导致商店里的变化。
现在,如果我们不在loggerMiddleware 内调用next 函数,会发生什么?
,那么动作将不会被发送到reducer,所以商店将不会被更新。
如果你使用过Node.js,那么你可能会发现这与中间件在Node.js中的工作方式类似。
在Node.js的中间件中,如果我们不调用下一个函数,请求将不会被向前发送。
这里有一个更新的代码沙盒演示,其中删除了下一个 函数的调用:
const loggerMiddleware = (store) => (next) => (action) => {
console.log("action", action);
};
这里是上述代码沙盒演示的预览链接。
如果你检查控制台,你会看到以下输出:

正如你所看到的,我们只得到记录在控制台的动作。而由于动作没有被转发到reducer,它将不会被执行--所以我们看不到来自store.subscribe 函数的console.log 。
正如前面所描述的,我们可以在动作被发送到还原器之前从中间件中修改动作。
下面是一个更新的代码沙盒演示,我们正在改变动作的有效载荷,然后再发送到还原器。
中间件的代码看起来像这样:
const loggerMiddleware = (store) => (next) => (action) => {
console.log("action", action);
action.payload = 3;
next(action);
};
这里是上述代码沙盒演示的预览链接:

按照代码,一旦动作被记录到控制台,我们就会将动作的有效载荷设置为3的值。所以动作type ,但payload 。
所以我们看到最初的状态变成了3。然后再次增加3,使之成为6。最后,它被减去3,使得最终的状态值为3。
在动作被发送到还原器之前,我们的loggerMiddleware 被调用,在那里我们改变了有效载荷的值,在它被发送到还原器之前我们总是将它设置为3。因此,基于动作类型INCREMENT或DECREMENT,还原器将总是被改变3的值。
即使我们在上面的代码中改变动作,在这种情况下也没有问题,因为它是一个中间件而不是一个还原器。
在上面的代码例子中,我们已经创建了一个单一的中间件。但你可以创建多个中间件,并像这样把它们传递给applyMiddleware 函数:
const middleware = applyMiddleware(loggerMiddleware, secondMiddleware, thirdMiddleware);
applyMiddleware 函数中提到的所有中间件将被一个接一个地执行。