zoukankan      html  css  js  c++  java
  • redux源码图解:createStore 和 applyMiddleware

    在研究 redux-saga时,发现自己对 redux middleware 不是太了解,因此,便决定先深入解读一下 redux 源码。跟大多数人一样,发现 redux源码 真的很精简,目录结构如下:

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

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

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

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

    这里,我可能不会仔细去分析它的源码,但会就自己的理解进行梳理概括,具体的对我很有帮助的文章会放到结尾参考处。

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

    redux源码图解之createStore和applyMiddleware

    1. 每个模块的作用

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

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

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

    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。

    // 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. 参考


  • 相关阅读:
    真机测试 iOS -- Coule not find Developer Disk Image
    XX
    Mac 控制 Mac
    在 mac 的 idea 中,查找 tomcat 解析 jsp 文件 后产生的 servlet 的位置
    mac idea 配置tomcat
    idea 普通Java项目转到web项目
    idea 新建java项目
    在mac上使用hexo和github创建博客
    解决git clone卡顿的一种思路
    10.【转载】nodeJS中读写文件方法的区别
  • 原文地址:https://www.cnblogs.com/Ruth92/p/7421697.html
Copyright © 2011-2022 走看看