Redux中间件为何采用三层返回?自定义applyMiddleware写法问题咨询
Redux applyMiddleware 核心疑问与代码问题分析
一、为什么applyMiddleware中的中间件需要先做映射?
applyMiddleware里对中间件做映射(即middlewares.map(middleware => middleware({ getState, dispatch }))),核心目的是给每个中间件注入store的上下文能力:
- 让所有中间件都能访问
getState方法,用于获取当前状态; - 注入一个特殊的
dispatch(通常是闭包引用最终包装后的dispatch),让中间件能在内部分发新的action; - 映射后,每个中间件会返回第二层函数
(next) => (action) => {},这是形成中间件链式调用的基础——compose工具可以把这些函数串联成一个执行链,最终和原始的store.dispatch对接。
二、为什么中间件要采用三层返回的结构?
Redux中间件的三层结构({ getState, dispatch }) => (next) => (action) => {}是为了实现洋葱模型的链式拦截逻辑,每一层的作用明确:
- 第一层:接收store上下文,让中间件拥有访问状态和分发动作的能力,这是中间件能完成复杂逻辑的基础(比如异步请求中间件需要获取当前状态里的token);
- 第二层:接收
next函数——这个next是链中下一个中间件的dispatch方法(或者最原始的store.dispatch),通过调用next(action)可以把动作传递给后续中间件或reducer;同时,这一层也让中间件能在next(action)前后插入逻辑(比如日志中间件:先打印action,调用next,再打印新状态); - 第三层:接收具体的action对象,执行实际的业务逻辑(比如判断action是否是函数,执行异步操作)。
如果去掉中间层(变成两层结构),就无法实现这种“前后拦截”的洋葱模型,也无法正确串联多个中间件。
三、你的自定义applyMiddleware和中间件写法存在的问题
1. 自定义applyMiddleware的逻辑错误
const applyMiddleware = (...middlewares) => { return (createStore) => (reducer, originState) => { const store = createStore(reducer, originState); const dispatch = compose(...middlewares)(store); // 核心错误 return { ...store, dispatch }; }; };
- 直接用
compose(...middlewares)(store)生成dispatch完全不符合中间件的调用逻辑:compose会把前一个中间件的返回值作为参数传给后一个中间件的第一层函数,但中间件的第一层应该接收store上下文,而不是另一个中间件的返回值(第二层函数); - 没有用闭包引用最终的dispatch,导致中间件里拿到的dispatch是原始的store.dispatch,无法分发经过中间件包装后的action。
正确的基础实现应该是:
const applyMiddleware = (...middlewares) => { return (createStore) => (reducer, preloadedState) => { const store = createStore(reducer, preloadedState); let dispatch = () => { throw new Error('Dispatch不能在中间件初始化时调用') }; const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) // 闭包引用最终的dispatch }; const chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); // 串联中间件链,对接原始dispatch return { ...store, dispatch }; }; };
2. 中间件的结构错误
applyMiddleware(({ getState, dispatch }) => { return (action) => { // 缺少接收next的第二层函数 if (typeof action === 'function') { action(dispatch); return; } dispatch(action); // 无限递归调用 }; })
- 中间件是两层结构,没有接收
next参数,无法形成链式调用,也无法把action传递给后续中间件或reducer; - 直接调用
dispatch(action)会导致无限递归:因为这个dispatch是你包装后的函数,调用它会再次进入当前中间件,再次执行dispatch(action),循环往复; - 处理异步action时,没有传入
getState也没有返回action执行的结果,不符合Redux中间件的规范。
正确的异步中间件(类似redux-thunk)写法应该是:
applyMiddleware(({ getState, dispatch }) => (next) => (action) => { if (typeof action === 'function') { return action(dispatch, getState); // 传入getState,返回执行结果 } return next(action); // 传递给下一个中间件或reducer })
内容的提问来源于stack exchange,提问作者ChenLee
相关产品推荐
相关产品推荐

