redux源码图解:createStore 和 applyMiddleware

在研究 redux-saga时,发现本身对 redux middleware 不是太了解,所以,便决定先深刻解读一下 redux 源码。跟大多数人同样,发现 redux源码 真的很精简,目录结构以下:javascript

|—— utils
    |—— warnings.js
|—— applyMiddleware.js
|—— bindActionCreator.js
|—— combineReducers.js
|—— compose.js
|—— createStore.js
|—— index.js

index.js 中导出了5个模块,即外部可用的:html

export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}

然而,当真正解读的时候,发现还真是有点吃不消,通过几天的硬啃以后,只能说:终于等到你,还好我没放弃。。。(自带BGM)java

这里,我可能不会仔细去分析它的源码,但会就本身的理解进行梳理归纳,具体的对我颇有帮助的文章会放到结尾参考处。react

首先是对 createStoreapplyMiddlewarecompose 的梳理,由于这3个模块存在相互调用的关系,其关系图以下(高清图请查看 redux源码图解之createStore和applyMiddleware):git

redux源码图解之createStore和applyMiddleware

1. 每一个模块的做用

createStore 的函数的做用就是生成一个 store 对象,这个对象具备5个方法:github

return {
    dispatch,  // 传入 action,调用 reducer 及触发 subscribe 绑定的监听函数
    subscribe,
    getState,
    replaceReducer,  // 用新的 reducer 代替当前的 reducer,使用很少
    [$$observable]: observable
  }

applyMiddleware 函数的做用就是对 store.dispatch 方法进行加强和改造,使得在发出 Action 和执行 Reducer 之间添加其余功能。redux

compose 函数则是 applyMiddleware 函数的核心,其会造成串联的函数调用关系,用于加强 dispatch 方法。数组

2. 模块之间的调用关系

(i) 首先,createStore 模块会对传入的参数进行判断,分别处理不一样参数的状况,当传入 applyMiddleware(...middleware) 的时候,就会返回 applyMiddleware(...middleware) 执行以后的高阶函数,即:架构

// createStore.js
if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    // 这里的 enhancer 是 applyMiddleware(...) 执行后的高阶函数,传参无 enhancer
    return enhancer(createStore)(reducer, preloadedState)
  }

(ii)而后,就进入了 applyMiddleware 模块内部的逻辑,从 createStore 返回的高阶函数,其传入的参数是没有 enhancer 的,所以走的是 createStore 函数中没有传入 enhancer 的逻辑,用于先得到没有中间件时返回的 store。app

// applyMiddleware.js
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []  // 用于存放获取了store的中间件数组

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

(iii)接着,获取最原始的 store 的 getStatedispatch,封装于 middlewareAPI 对象。将该对象传入中间件 middleware 中,造成中间件数组 chain

其中,middleware 的范式是:(store) => (next) => (action) => {},将 middlewareAPI 传入middleware 后,中间件便得到了 {getState, dispacth}。至此,chain 中间件数组中包含的每一个中间件的形式都变成了 (next) => (action) => {} 的形式。

(iiii)最后,调用 compose 函数,如 chian = [middleware1, middleware2, middleware3],则 dispatch = compose(...chain)(store.dispatch),即执行 middleware1(middleware2(middleware3(store.dispatch))),而后赋值给 dispatch

总之,无论是否有 applyMiddlewarecreateStore 的结果都是输出一个 store 对象,而 applyMiddleware 则能够对 store 对象中的 dispatch 进行改造。

3. 参考

相关文章
相关标签/搜索