在看候策与严海镜写的《React状态管理与同构实践》的时候,在第四章第六节(4.6.1:Redux源码探索--中间件的秘密),
作者在关键地方出了一个错误,这个错误导致了我一个上午都在推演程序的流程,因为我无论如何推结果都不对。
所以我找到了Redux的源码,一对比才确定了这个错误,现将这个错误贴出来,希望看此书的人不再迷惑。
出错源码:
export const applyMiddleware = (...middlewares) => createStore => (reducer, preloadState) => {
const store = createStore(reducer, preloadState)
const dispatch = store.dispatch
const chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: action => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
//出错位置
dispatch = compose(...chain, dispatch) //React状态管理与同构实践--错误
dispatch = compose(...chain)(store.dispatch) //redux源码--正确
return {
...store,
dispatch
}
}
其中的关键点:compose源码:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
举例分析:
先附上Array.prototype.reduce()的使用方法:
例子:若只有a,b两个中间件,那么最后增强之后的store.dispatch的差异如下:
- 错误分析:
dispatch = compose(...chain, dispatch) //React状态管理与同构实践--错误
增强之后的dispatch:
store.dispatch = (...args) => a(b(store.dispatch))
a,b此时是两阶柯里化的函数(原始定义的中间件是三阶柯里化的形式,在chain = middlewares.map(middleware => middleware(middlewareAPI))的时候执行了一阶),形式如下:
const a = next => action => {...}
const b = next => action => {...}
所以还需要执行两步。但是当以store.dispatch = (...args) => a(b(store.dispatch))的形式调用dispatch(action)时,直接返回了a(b(store.dispatch))的执行结果,也就是说每个中间件的执行还差了一步,而且也没有接收action。所以这种逻辑肯定是错误的。
- 正确分析:
dispatch = compose(...chain)(store.dispatch) //redux源码--正确
增强之后的dispatch:
store.dispatch = a(b(store.dispatch))
此时若执行store.dispatch(action) 等价于 a(b(store.dispatch))(action),可以看出每个二阶的中间件均执行了两次。逻辑正确。
在此希望出书的作者能细心一些,肯出钱买你书的人都是十分信赖你的人