zoukankan      html  css  js  c++  java
  • Redux 源码阅读记录

    一,背景

    Redux在mobx之前出现,redux基于Elm, flux, Immutable.js 的思想对状态管理重新做了优化。

    在项目中使用时,Redux对数据更新和管理,可以很容易扩展插件,中间件等。

    二,redux提供的api

    1,compose

    对传入的函数进行从右往左的方式编译,函数的合并。

    代码实现如下:

    /**
     * 从右往左,编译单个参数的函数。最右函数可以是多个参数的函数,提供单个编译函数。
     *
     * @param {...Function} funcs The functions to compose.
     * @returns {Function} A function obtained by composing the argument functions
     * from right to left. 
    * For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))).
    */ function compose() { for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { funcs[_key] = arguments[_key]; } if (funcs.length === 0) { return function (arg) { return arg; }; } if (funcs.length === 1) { return funcs[0]; } // reduce 多次回归调用,函数是一个包裹的过程,从左往右包裹,执行时从右往左执行。
    // 最后返回一个可以执行所有函数的 函数!
    return funcs.reduce(function (a, b) { return function () { return a(b.apply(void 0, arguments)); }; }); }

    2,bindActionCreator / bindActionCreators

    将action和dispatch合并,作为action的creator。

    // 源码这里 调用函数会返回一个函数,函数执行会返回dispatch执行action的结果,相当于提前执行了dispatch。
    function
    bindActionCreator(actionCreator, dispatch) { return function () { return dispatch(actionCreator.apply(this, arguments)); }; }

    bindActionCreator 是为了提前获取dispatch action的结果,还提供了bindActionCreators

    /**
     * 
    * 转换每一个action creator,将其返回的对象的key都进行 dispatch 包裹,方便直接调用。
    * 为了方便,也可以在creator 的第一个参数传入dispatch,用dispatch包裹后再返回。 * * @param {Function|Object} actionCreators An object whose values are action * creator functions. One handy way to obtain it is to use ES6 `import * as` * syntax. You may also pass a single function.
    * 和es6 的 import * as 语法结合使用,传入对象或者函数。 * * @param {Function} dispatch The `dispatch` function available on your Redux * store. *
    */ function bindActionCreators(actionCreators, dispatch) {
    // 判断是否是函数
    if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators, dispatch); }
    // 判断是否是不是null的对象
    if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error("bindActionCreators expected an object or a function, instead received " + (actionCreators === null ? 'null' : typeof actionCreators) + ". " + "Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?"); } // 定义新对象,存储传参对象调用 bindActionCreator 的返回值。 var boundActionCreators = {}; // 如果是对象执行 for-in 循环(for-in专用于遍历对象的key。) for (var key in actionCreators) { var actionCreator = actionCreators[key]; // 对每个对象中的function都调用一次上面的 bindActionCreator() 函数。 if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); } } // 返回新的对象 return boundActionCreators; }

    3,applyMiddleware

    应用中间件,用于丰富redux的功能。
    一般写法是这样的。
    const composeEnhancers = composeWithDevTools({ actionCreators, trace: true, traceLimit: 25 });
        const store = createStore(reducer, preloadedState, composeEnhancers(
            // 引入中间件的方式
    applyMiddleware(invariant(), thunk)
    ));
    return store; ));

    查看这个中间件需要先看一个关键的函数:_objectSpread2

    _objectSpread2 函数代码如下

    // es6 的方式把对象的key
    function
    ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) {
    // push.apply 数组的合并,获取可枚举的key + 符号类型的key(是否可枚举都获取到),得到完整的key数组。 keys.push.apply(keys, Object.getOwnPropertySymbols(object)); } // 过滤掉不能枚举的属性
    if (enumerableOnly) keys = keys.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); return keys; // 返回对象的key数组 }
    // redux加载中间件 关键的函数
    //
    function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {};
    // 如果资源的下标是偶数
    if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
    以下是 applyMiddleware 源码的实现:
    /**
     * 
     * 引用中间件以丰富修改 redux store 的dispatch方法。
    * 满足不同的任务,用简明的方式实现,例如:异步action,日志等。
    * * 参考 `redux-thunk` 就是处理异步的中间件。 * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain.
    * 因为中间件是潜在的异步过程,应该是在组和链中第一个被调用 * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments.
    * 每个中间件都应该有 dispatch 和 getState 方法。 * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware.
    * 然后返回应用中间件的store enhancer 状态值的放大器。

    * 重点意思是,对action的再次封装返回新的action。
    */ function applyMiddleware() {
    // 遍历函数arguments,并将参数重新收集到一个新的 middlewares 数组。
    for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) { middlewares[_key] = arguments[_key]; } return function (createStore) { return function () { var store = createStore.apply(void 0, arguments);
    // 引用中间件不被允许的提示。
    var _dispatch = function dispatch() { throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.'); };
    // store的 getState dispatch 方法,拿过来给每个中间件都是
    var middlewareAPI = { getState: store.getState, dispatch: function dispatch() { return _dispatch.apply(void 0, arguments); } }; var chain = middlewares.map(function (middleware) {
    // 将getState和dispatch传递给中间件
    return middleware(middlewareAPI); });

    //把添加getState和dispatch的中间件数组,调用 compose 进行一次dispatch的合并,返回一个函数再次调用得到新的dispatch。 _dispatch
    = compose.apply(void 0, chain)(store.dispatch); return _objectSpread2({}, store, { dispatch: _dispatch }); }; }; }

    4,composeEnhancers

  • 相关阅读:
    pt-tcp-model
    (转)从史上八大MySQL宕机事故中学到的经验
    pt-query-digest
    DNS生效时间
    Python之uuid模块
    一个IO的传奇一生
    Python之Queue模块
    利用freemarker 静态化网页
    FreeMarker教程
    模板引擎freemarker的简单使用教程
  • 原文地址:https://www.cnblogs.com/the-last/p/11634455.html
Copyright © 2011-2022 走看看