《React状态管理与同构实践》(候策&严海镜)勘误

451 阅读2分钟

在看候策与严海镜写的《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),可以看出每个二阶的中间件均执行了两次。逻辑正确。

在此希望出书的作者能细心一些,肯出钱买你书的人都是十分信赖你的人