“next”在react-redux中间件中如何工作?

Jas*_*llo 5 javascript reactjs redux react-redux

我是 React 和 Redux 的新手。我有一个简单的应用程序,您可以在其中将输入文本添加到无序列表中。我有中间件可以防止显示特定单词。我不明白实现中间件的操作顺序。据我了解,当我触发调度时,会发生以下情况:

  1. 从表单提交事件触发调度
// title is an object with a string
function handleSubmit(event) {
    props.addArticle(title);
}
Run Code Online (Sandbox Code Playgroud)
  1. 遍历中间件函数:
// store.js
const store = createStore(
  rootReducer, // this is defined elsewhere and effectively handles actions
  applyMiddleware(forbiddenWordsMiddleware)
);
Run Code Online (Sandbox Code Playgroud)
// middleware.js
import { ADD_ARTICLE } from "../constants/constants.js";
const forbiddenWords = ["spam", "money"];
export function forbiddenWordsMiddleware({ dispatch }) {
    return function (next) {
        return function (action) {
            if (action.type === ADD_ARTICLE) {
                const foundWord = forbiddenWords.filter((word) =>
                    action.payload.title.includes(word)
                );
                if (foundWord.length) {
                    return dispatch({ type: "FOUND_BAD_WORD" });
                }
            }
            return next(action);
        };
    };
}
Run Code Online (Sandbox Code Playgroud)

上述函数实际上如何与 createStore 和 applyMiddleware 配合使用?尤其令我困惑的是这next(action)条线。下一步和行动从何而来?我无法想象从表单提交到检查禁用词的线性执行。

mar*_*son 9

中间件围绕实际的 Redux 函数形成管道store.dispatch。当您调用 时store.dispatch(action),您实际上是在调用链中的第一个中间件。在中间件内部,next将值传递给下一个中间件,同时storeAPI.dispatch重新启动管道action是传递给dispatch(或传递给next(或从前一个中间件

这种可视化可能会有所帮助:

Redux中间件管道图

不可否认,实际的实现是有点神奇的代码,但您不需要担心。

有关更多详细信息,请参阅我的“Redux 基础研讨会”幻灯片的“可扩展性和中间件”部分,以及有关 Redux 中间件如何工作的这些文章


Edd*_*oro 8

在这种情况下,next仅仅意味着该中间件对该特定操作不感兴趣,并且希望将其传递给其他中间件来处理它。

当您将中间件提供给 applyMiddleware 函数时,它首先调用每个中间件并向其传递名为middlewareAPI here的内容。然后从最后一个中间件开始,调用它并给出store.dispatch然后将其结果发送到最后一个中间件之前的中间件。继续这样(将后面的中间件的结果传递给前面的中间件)一直到第一个中间件。

假设您有这三个中间件:[a, b, c]并将它们全部传递给 applyMiddleware 函数。这是发生的事情:

  1. 首先,每个中间件都使用该middlewareAPI对象进行调用,该对象基本上是一个包含原始store.dispatch和 的对象store.getState

    const middlewareAPI = { getState: store.getState, dispatch: store.dispatch }
    const aInChain = a(middlewareAPI);
    const bInChain = b(middlewareAPI);
    const cInChain = c(middlewareAPI);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 其次,我们使用前一个中间件调用的结果来调用每个中间件。预计最后一个中间件后面没有任何内容,并获取原始调度作为输入。

    const finalC = cInChain(store.dispatch);
    const finalB = bInChain(finalC);
    const finalA = aInChain(finalB);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后,我们设置第一个中间件的最终版本,作为新增强存储的调度。因此,例如,当您调用 时store.dispatch({ type: "Hello" }),该finalA函数将被调用,并且如果它调用finalB作为 提供给它的函数next,则链中的下一个中间件将被调用,并执行finalA给它的任何操作。整个链条都是这样。

因此,在我们问题中的示例中,中间件中有两个 return 语句。第一个是return dispatch({...}),第二个是return next({...})

在这两种情况下,我们的中间件都表示它已完成此操作的工作并让调度链继续;但在第一个 return 语句中,中间件dispatch直接调用原始语句并将具有新类型的新操作传递给dispatch. 因此,最初传递给中间件的操作将被完全遗忘。该语句在操作到达存储之前打破了中间件链,并使用新操作启动新的调度。

在第二次返回中,我们的中间件调用该next函数,正如我之前所描述的,它是该行中的下一个中间件,并且我们的中间件将原始数据发送action给它而不更改任何内容。所以结果就像这个中间件根本不存在一样。

在这种情况下,我们的中间件只是说“我不关心这个动作是什么;我想将它发送到下一个中​​间件来决定它是否应该到达store.dispatch”。