`

dva

 
阅读更多

dva模块基于redux、redux-saga、react-router实现,用于配置路由,state处理逻辑等。

"version": "1.2.1"

 

index.js

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = require('./lib');
exports.connect = require('react-redux').connect;

 

lib/index.js

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _hashHistory = require('react-router/lib/hashHistory');
var _hashHistory2 = _interopRequireDefault(_hashHistory);

var _reactRouterRedux = require('react-router-redux');

var _createDva = require('./createDva');
var _createDva2 = _interopRequireDefault(_createDva);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.default = (0, _createDva2.default)({
  mobile: false,
  initialReducer: {
    routing: _reactRouterRedux.routerReducer
  },
  defaultHistory: _hashHistory2.default,
  routerMiddleware: _reactRouterRedux.routerMiddleware,

  setupHistory: function setupHistory(history) {
    this._history = (0, _reactRouterRedux.syncHistoryWithStore)(history, this._store);
  }
});
module.exports = exports['default'];

 

lib/createDva.js核心模块

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);

var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);

// 浅拷贝
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);

var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);

exports.default = createDva;

var _react = require('react');
var _react2 = _interopRequireDefault(_react);

var _reactRedux = require('react-redux');

var _redux = require('redux');

var _middleware = require('redux-saga/lib/internal/middleware');
var _middleware2 = _interopRequireDefault(_middleware);

var _effects = require('redux-saga/effects');
var sagaEffects = _interopRequireWildcard(_effects);

var _isPlainObject = require('is-plain-object');
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);

var _invariant = require('invariant');
var _invariant2 = _interopRequireDefault(_invariant);

var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);

var _flatten = require('flatten');
var _flatten2 = _interopRequireDefault(_flatten);

var _window = require('global/window');
var _window2 = _interopRequireDefault(_window);

var _document = require('global/document');
var _document2 = _interopRequireDefault(_document);

var _sagaHelpers = require('redux-saga/lib/internal/sagaHelpers');

var _lodash = require('lodash.isfunction');
var _lodash2 = _interopRequireDefault(_lodash);

var _handleActions = require('./handleActions');
var _handleActions2 = _interopRequireDefault(_handleActions);

var _plugin = require('./plugin');
var _plugin2 = _interopRequireDefault(_plugin);

function _interopRequireWildcard(obj) { 
  if (obj && obj.__esModule) { 
    return obj; 
  } else { 
    var newObj = {}; 
    if (obj != null) { 
      for (var key in obj) { 
        if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; 
      } 
    } 
    newObj.default = obj; return newObj; 
  } 
}

function _interopRequireDefault(obj) { 
  return obj && obj.__esModule ? obj : { default: obj }; 
}

var SEP = '/';

function createDva(createOpts) {
  var mobile = createOpts.mobile,
      initialReducer = createOpts.initialReducer,// 默认require('react-router-redux').routerReducer
      defaultHistory = createOpts.defaultHistory,// 默认'react-router/lib/hashHistory'
      routerMiddleware = createOpts.routerMiddleware,// 默认require('react-router-redux').routerMiddleware
      setupHistory = createOpts.setupHistory;

  /**
   * Create a dva instance.
   */

  return function dva() {
    var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    // history and initialState does not pass to plugin
    var history = hooks.history || defaultHistory;
    var initialState = hooks.initialState || {};
    delete hooks.history;
    delete hooks.initialState;

    var plugin = new _plugin2.default();
    plugin.use(hooks);

    var app = {
      // properties
      _models: [],
      _router: null,
      _store: null,
      _history: null,
      _plugin: plugin,
      // methods

      // dva.use(plugin={key:fn})添加钩子函数
      // 当key为'extraEnhancers',值须为数组形式,该值将替换plugin.hooks.extraEnhancers,用于添加redux中间件
      //    当key为其他时,名义上没有限制类型,且使用push方法添加到plugin.hooks[key]中
      // 当key为'extraReducers',值须为{actionType:reducer()=>{}},且actionType不能和任意model对象的命名空间重名
      //    用于添加额外的reducer
      // 当key为'onReducer'时,值须为fn,用于装饰redux.combineReducers返回值
      // 当key为'onAction'时,值须为fn,用于添加redux中间件如redux-logger等
      // 当key为'onStateChange'时,值须为fn,redux机制的dispatch方法执行修改state时,触发调用fn监听函数
      // 当key为'onEffect'时,值须为fn(effect,sagaEffects,model,key),用于装饰model.effects中各生成器函数
      use: use,

      // dva.model({namespace,state,subscriptions,reducers,effects}),向this._models添加经属性名转换后的model对象
      // 参数model.reducers={actionType:reducer(state,action)=>{}}
      //    或者model.reducers=[{actionType:reducer(state,action)=>{}},wrap((state,action)=>{}){}]
      //    前者单纯设定actionType该调用执行的reducer以修改state
      //    后者除设定actionType下该调用的reducer以外,还可对handleActions流程控制函数作包装
      model: model,
      
      // dva.router(fn)形式配置路由规则,this._router=router
      router: router,
      start: start
    };
    return app;

    // //////////////////////////////////
    // Methods

    // dva.use(plugin={key:fn})添加钩子函数
    function use(hooks) {
      plugin.use(hooks);
    }

    // dva.model({ namespace, state, subscriptions, reducers, effects })向this._models添加经属性名转换后的model对象
    // model.effects可以是对象或数组,对象其属性值为生成器函数,参数为封装put方法后的sagaEffects对象
    //    若为数组,第二项为配置项opts,且
    //        opts.type须是['watcher', 'takeEvery', 'takeLatest', 'throttle']中的一个
    //        opts.type若为'throttle',则opts.ms必须存在
    function model(model) {
      // checkModel函数校验model模块的namespace、subscriptions、reducers、effects属性
      //    同时将model.reducers、model.reducers[0]、model.effects对象的属性名转换为namespace+"/"+key形式
      // 经过属性名转换后的model对象存入this._models中
      this._models.push(checkModel(model, mobile));
    }

    // 由bind方法将injectModel赋值给this.model,用于注入特定的m
    function injectModel(createReducer, onError, unlisteners, m) {
      m = checkModel(m, mobile);
      this._models.push(m);
      var store = this._store;

      // reducers
      // getReducer函数获取根据action.type调用相应model.reducer[action.type]以修改state的的流程控制函数;或者顺序传递state
      store.asyncReducers[m.namespace] = getReducer(m.reducers, m.state);
      store.replaceReducer(createReducer(store.asyncReducers));
      // effects
      if (m.effects) {
        store.runSaga(getSaga(m.effects, m, onError));
      }
      // subscriptions
      if (m.subscriptions) {
        unlisteners[m.namespace] = runSubscriptions(m.subscriptions, m, this, onError);
      }
    }

    // 由bind方法将unmodel赋值给this.unmodel,用于以namespace移除特定的model
    function unmodel(createReducer, reducers, _unlisteners, namespace) {
      var store = this._store;

      // Delete reducers
      delete store.asyncReducers[namespace];
      delete reducers[namespace];
      store.replaceReducer(createReducer(store.asyncReducers));
      store.dispatch({ type: '@@dva/UPDATE' });

      // Cancel effects
      store.dispatch({ type: namespace + '/@@CANCEL_EFFECTS' });

      // unlisten subscrioptions
      if (_unlisteners[namespace]) {
        var _unlisteners$namespac = _unlisteners[namespace],
            unlisteners = _unlisteners$namespac.unlisteners,
            noneFunctionSubscriptions = _unlisteners$namespac.noneFunctionSubscriptions;

        (0, _warning2.default)(noneFunctionSubscriptions.length === 0, 'app.unmodel: subscription should return unlistener function, check these subscriptions ' + noneFunctionSubscriptions.join(', '));
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = (0, _getIterator3.default)(unlisteners), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var unlistener = _step.value;

            unlistener();
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator.return) {
              _iterator.return();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }

        delete _unlisteners[namespace];
      }

      // delete model from this._models
      this._models = this._models.filter(function (model) {
        return model.namespace !== namespace;
      });
    }

    // dva.router(fn)形式配置路由规则
    function router(router) {
      (0, _invariant2.default)(typeof router === 'function', 'app.router: router should be function');
      this._router = router;
    }

    // 启动,转化redux配置,添加router配置,挂载渲染组件或返回组件
    function start(container) {
      // 通过container获取容器节点,并校验该容器节点为html元素
      if (typeof container === 'string') {
        container = _document2.default.querySelector(container);
        (0, _invariant2.default)(container, 'app.start: could not query selector: ' + container);
      }
      (0, _invariant2.default)(!container || isHTMLElement(container), 
        'app.start: container should be HTMLElement');

      // 校验dva.router(fn)方法得到执行,即this._router有值
      (0, _invariant2.default)(this._router, 'app.start: router should be defined');

      // plugin.apply('onError',defaultHandler)注册默认"onError"事件处理函数defaultHandler,即抛出错误
      // 若客户使用dva.use({onError:fn})注册"onError"事件处理钩子时,onError函数执行时将调用fn(err,dispatch)函数,同时不调用defaultHandler
      var onError = plugin.apply('onError', function (err) {
        throw new Error(err.stack || err);
      });
      var onErrorWrapper = function onErrorWrapper(err) {
        if (err) {
          if (typeof err === 'string') err = new Error(err);
          onError(err, app._store.dispatch);
        }
      };

      // internal model for destroy
      // dva.model({ namespace, state, subscriptions, reducers, effects })向this._models添加经属性名转换后的model对象
      model.call(this, {
        namespace: '@@dva',
        state: 0,
        reducers: {
          UPDATE: function UPDATE(state) {
            return state + 1;
          }
        }
      });

      // get reducers and sagas from model
      var sagas = [];
      var reducers = (0, _extends3.default)({}, initialReducer);// 存储各model的流程控制函数
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      // 以迭代器形式将this._models中各model.reducers转化为流程控制函数,添加到reducers[model.namespace]中
      // 流程控制函数中,当传参action.type与model.reducers的属性名相符,修改state;不符,顺序传递state
      try {
        for (var _iterator2 = (0, _getIterator3.default)(this._models), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var m = _step2.value;

          // getReducer函数获取根据action.type调用相应model.reducer[action.type]以修改state的的流程控制函数
          // 或者顺序传递state
          reducers[m.namespace] = getReducer(m.reducers, m.state);

          // getSaga函数构建生成器函数,迭代model.effects各生成器函数,设置action并作相应处理
          if (m.effects) sagas.push(getSaga(m.effects, m, onErrorWrapper));
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      // dva.use({'extraReducers':{actionType:reducer()=>{}}})以数组形式将fn存储在plugin.hooks.extraReducers中
      // 即plugin.hooks.extraReducers数组元素各对象的属性名不能与任意model对象的命名空间重名
      var extraReducers = plugin.get('extraReducers');
      (0, _invariant2.default)((0, _keys2.default)(extraReducers).every(function (key) {
        return !(key in reducers);
      }), 'app.start: extraReducers is conflict with other reducers');

      // dva.use({'extraReducers':[]})替换plugin.hooks.extraEnhancers形式添加'extraEnhancers'钩子
      var extraEnhancers = plugin.get('extraEnhancers');
      (0, _invariant2.default)(Array.isArray(extraEnhancers), 
        'app.start: extraEnhancers should be array');

      // 创建redux的中间件middlewares,使用redux.applyMiddleware方法完成挂载
      var extraMiddlewares = plugin.get('onAction');
      var reducerEnhancer = plugin.get('onReducer');
      var sagaMiddleware = (0, _middleware2.default)();// redux中间件机制为着装饰dispatch方法
      var middlewares = [sagaMiddleware].concat((0, _toConsumableArray3.default)((0, _flatten2.default)(extraMiddlewares)));
      if (routerMiddleware) {
        middlewares = [routerMiddleware(history)].concat((0, _toConsumableArray3.default)(middlewares));
      }
      var devtools = function devtools() {
        return function (noop) {
          return noop;
        };
      };
      if (process.env.NODE_ENV !== 'production' && _window2.default.__REDUX_DEVTOOLS_EXTENSION__) {
        devtools = _window2.default.__REDUX_DEVTOOLS_EXTENSION__;
      }
      var enhancers = [_redux.applyMiddleware.apply(undefined, (0, _toConsumableArray3.default)(middlewares)), devtools()].concat((0, _toConsumableArray3.default)(extraEnhancers));
      
      // 创建redux的store
      var store = this._store = (0, _redux.createStore)(createReducer(), initialState, _redux.compose.apply(undefined, (0, _toConsumableArray3.default)(enhancers)));

      // 通过plugin.hooks.onReducer数组中函数装饰redux.combineReducers返回值
      function createReducer(asyncReducers) {
        return reducerEnhancer((0, _redux.combineReducers)((0, _extends3.default)({}, reducers, extraReducers, asyncReducers)));
      }

      // extend store
      store.runSaga = sagaMiddleware.run;
      store.asyncReducers = {};

      // dva.use({onStateChange:fn()=>{}})绑定dispatch执行修改state时将触发的fn监听函数
      var listeners = plugin.get('onStateChange');
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      // store.subscribe(fn)方法当dispatch方法执行修改state时调用fn
      try {
        for (var _iterator3 = (0, _getIterator3.default)(listeners), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var listener = _step3.value;

          store.subscribe(listener);
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3.return) {
            _iterator3.return();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      // require('redux-saga/lib/internal/middleware').middleware添加redux-saga中间件
      // sagaMiddleware.run(sage)设定redux-saga中间件的运行逻辑
      // redux-saga机制???
      sagas.forEach(sagaMiddleware.run);

      // 设定history
      if (setupHistory) setupHistory.call(this, history);

      // 组件渲染完成当即执行model.subscription中各方法,派发action,返回解绑函数集合
      var unlisteners = {};
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = (0, _getIterator3.default)(this._models), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var _model = _step4.value;

          if (_model.subscriptions) {
            unlisteners[_model.namespace] = runSubscriptions(_model.subscriptions, _model, this, onErrorWrapper);
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      this.model = injectModel.bind(this, createReducer, onErrorWrapper, unlisteners);

      this.unmodel = unmodel.bind(this, createReducer, reducers, unlisteners);

      // 若容器节点存在,挂载组件;不存在,返回react组件
      if (container) {
        render(container, store, this, this._router);
        plugin.apply('onHmr')(render.bind(this, container, store, this));
      } else {
        return getProvider(store, this, this._router);
      }
    }

    // //////////////////////////////////
    // Helpers

    // 返回react组件
    function getProvider(store, app, router) {
      return function (extraProps) {
        return _react2.default.createElement(
          _reactRedux.Provider,
          { store: store },
          router((0, _extends3.default)({ app: app, history: app._history }, extraProps))
        );
      };
    }

    // 挂载组件
    function render(container, store, app, router) {
      var ReactDOM = require('react-dom');
      ReactDOM.render(_react2.default.createElement(getProvider(store, app, router)), container);
    }

    // 校验model模块的namespace、subscriptions、reducers、effects属性
    // 同时将model.reducers、model.reducers[0]、model.effects对象的属性名转换为namespace+"/"+key形式
    function checkModel(m, mobile) {
      var model = (0, _extends3.default)({}, m);
      var namespace = model.namespace,
          reducers = model.reducers,
          effects = model.effects;

      // 校验model.namespace属性不能为空,不能重复,且mobile为否值时不能赋值为'routing'
      (0, _invariant2.default)(namespace, 'app.model: namespace should be defined');
      (0, _invariant2.default)(!app._models.some(function (model) {
        return model.namespace === namespace;
      }), 'app.model: namespace should be unique');
      (0, _invariant2.default)(mobile || namespace !== 'routing', 
        'app.model: namespace should not be routing, it\'s used by react-redux-router');
      
      // 校验model.subscriptions属性为普通对象
      (0, _invariant2.default)(!model.subscriptions || (0, _isPlainObject2.default)(model.subscriptions), 'app.model: subscriptions should be Object');
      
      // 校验model.reducers属性须为对象或数组
      (0, _invariant2.default)(!reducers || (0, _isPlainObject2.default)(reducers) || 
        Array.isArray(reducers), 'app.model: reducers should be Object or array');
      // 校验当model.reducers为数组时,其首项须为对象,第二项须为函数
      (0, _invariant2.default)(!Array.isArray(reducers) || (0, _isPlainObject2.default)(reducers[0]) 
        && typeof reducers[1] === 'function', 
        'app.model: reducers with array should be app.model({ reducers: [object, function] })');

      // 校验model.effects须为对象
      (0, _invariant2.default)(!effects || (0, _isPlainObject2.default)(effects), 
        'app.model: effects should be Object');

      function applyNamespace(type) {
        // 将model.reducers、model.reducers[0]、model.effects对象的属性名转换为namespace+"/"+key形式
        function getNamespacedReducers(reducers) {
          return (0, _keys2.default)(reducers).reduce(function (memo, key) {
            // 校验model.reducers、model.reducers[0]、model.effects对象的属性不能以namespace+"/"起始
            (0, _warning2.default)(key.indexOf('' + namespace + SEP) !== 0, 
              'app.model: ' + type.slice(0, -1) + ' ' + key + 
                ' should not be prefixed with namespace ' + namespace);
            memo['' + namespace + SEP + key] = reducers[key];
            return memo;
          }, {});
        }

        if (model[type]) {
          if (type === 'reducers' && Array.isArray(model[type])) {
            model[type][0] = getNamespacedReducers(model[type][0]);
          } else {
            model[type] = getNamespacedReducers(model[type]);
          }
        }
      }

      // 将model.reducers或model.reducers[0]对象的属性名转换为namespace+"/"+key形式
      applyNamespace('reducers');
      // 将model.effects对象的属性名转换为namespace+"/"+key形式
      applyNamespace('effects');

      return model;
    }

    // 是否html节点元素
    function isHTMLElement(node) {
      return (typeof node === 'undefined' ? 'undefined' : 
        (0, _typeof3.default)(node)) === 'object' && node !== null && node.nodeType && node.nodeName;
    }

    // 获取根据action.type调用相应model.reducer[action.type]以修改state的的流程控制函数;或者顺序传递state
    function getReducer(reducers, state) {
      // model.reducers为数组时,调用model.reducers[1]包装handleActions流程控制函数的返回值
      // handleActions流程控制函数用于设定特定action.type下该调用的reducer函数以修改state
      //    其返回值为函数(state,action)=>{},根据action.type调用model.reducers中相应的reducer;或顺序传递state
      if (Array.isArray(reducers)) {
        return reducers[1]((0, _handleActions2.default)(reducers[0], state));
      } else {
        return (0, _handleActions2.default)(reducers || {}, state);
      }
    }

    // regenerator.mark(fn)将fn.prototype赋值为迭代器的原型对象并附以next、return、throw方法后返回fn
    //    若将封装后的fn作为参数outerFn传入regenerator.wrap方法中,wrap内获取fn.prototype迭代器原型,为其添加_invoke方法后返回
    // regenerator.wrap(innerFn,outerFn,self,tryLocsList)方法获取outerFn.prototype迭代器原型或默认迭代器原型
    //    为其添加_invoke方法后返回,从而其返回值next方法执行时将调用innerFn特定条件分支,throw方法报错,return执行完成
    // regenerator.keys(object)遍历取出object对象的属性名集合,调用返回值函数,类迭代形式取出反序排列的该属性名集合
    // context.delegateYield(iterator,resultName,nextLoc)调用时将使iterator替代innerFn输出内容,通过nextLoc跳回到innerFn取值

    // 以生成器函数逻辑处理model.effects各属性,next方法逐层调用时将获取{context:null,fn:watcher,args:undefined}
    // watcher为getWatcher函数包装model.effects[key]后的生成器函数,用于设置action,并取出fn=sagaWithCatch
    // sagaWithCatch函数的逻辑中,报错时将跳转onError函数内
    function getSaga(effects, model, onError) {
      return _regenerator2.default.mark(function _callee3() {
        var _this = this;

        var key;
        return _regenerator2.default.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                _context3.t0 = _regenerator2.default.keys(effects);

              case 1:
                if ((_context3.t1 = _context3.t0()).done) {
                  _context3.next = 7;
                  break;
                }

                key = _context3.t1.value;

                if (!Object.prototype.hasOwnProperty.call(effects, key)) {
                  _context3.next = 5;
                  break;
                }

                // context.delegateYield被调用时将代替_callee3$输出内容,即先取_callee2生成器输出内容
                //    _callee2生成器中,通过对_context.next赋值,跳出_callee2生成器,并回到_callee3$取值
                return _context3.delegateYield(_regenerator2.default.mark(function _callee2() {
                  var watcher, task;
                  return _regenerator2.default.wrap(function _callee2$(_context2) {
                    while (1) {
                      switch (_context2.prev = _context2.next) {
                        case 0:
                          // watcher赋值为getWatcher创建的生成器函数
                          watcher = getWatcher(key, effects[key], model, onError);
                          _context2.next = 3;
                          // sagaEffects.fork返回{context:null,fn:watcher,args:undefined}
                          return sagaEffects.fork(watcher);

                        case 3:
                          task = _context2.sent;
                          _context2.next = 6;
                          return sagaEffects.fork(_regenerator2.default.mark(function _callee() {
                            return _regenerator2.default.wrap(function _callee$(_context) {
                              while (1) {
                                switch (_context.prev = _context.next) {
                                  case 0:
                                    _context.next = 2;
                                    // sagaEffects.take返回{[IO]:true,TAKE:model.namespace+'/@@CANCEL_EFFECTS'}
                                    return sagaEffects.take(model.namespace + '/@@CANCEL_EFFECTS');

                                  case 2:
                                    _context.next = 4;
                                    // sagaEffects.cancel返回{[IO]:true,CANCEL:task}
                                    // task即_callee2$条件分支case 0下返回值{context:null,fn:watcher,args:undefined}
                                    return sagaEffects.cancel(task);

                                  case 4:
                                  case 'end':
                                    return _context.stop();
                                }
                              }
                            }, _callee, this);
                          }));

                        case 6:
                        case 'end':
                          return _context2.stop();
                      }
                    }
                  }, _callee2, _this);
                })(), 't2', 5);

              // next方法再次调用时,model.effects其中一个属性已经处理完成,跳回到条件分支1,处理下一个model.effects属性
              case 5:
                _context3.next = 1;
                break;

              case 7:
              case 'end':
                return _context3.stop();
            }
          }
        }, _callee3, this);
      });
    }

    // 构建生成器函数
    // 当type="watcher",返回sagaWithCatch生成器函数,其返回值的next方法调用时将执行effect生成器函数
    // 当type="takeEvery",返回值的next方法二次调用时将设定action,并输出{context,fn:sagaWithCatch,args:action}
    function getWatcher(key, _effect, model, onError) {
      var _marked = [sagaWithCatch].map(_regenerator2.default.mark);

      var effect = _effect;
      var type = 'takeEvery';
      var ms = void 0;

      // model.effect为数组时,第二项为配置项opts
      //    opts.type须是['watcher', 'takeEvery', 'takeLatest', 'throttle']中的一个
      //    opts.type若为'throttle',则opts.ms必须存在
      if (Array.isArray(_effect)) {
        effect = _effect[0];
        var opts = _effect[1];
        if (opts && opts.type) {
          type = opts.type;
          if (type === 'throttle') {
            (0, _invariant2.default)(opts.ms, 'app.start: opts.ms should be defined if type is throttle');
            ms = opts.ms;
          }
        }
        (0, _invariant2.default)(['watcher', 'takeEvery', 'takeLatest', 'throttle'].indexOf(type) > -1, 
          'app.start: effect type should be takeEvery, takeLatest, throttle or watcher');
      }

      // 跟编译后的生成器函数相似,调用sagaWithCatch获取regenerator.wrap装饰后的generator函数
      // 调用返回值generator函数的next方法,执行effect生成器函数;若报错,则使用onError函数捕获错误
      // generator函数的next方法的返回值逐步调用next方法,即执行effect生成器函数内yield语句
      function sagaWithCatch() {
        var _len,
            args,
            _key,
            _args4 = arguments;

        // effect生成器函数本身经过babel编译
        // 再使用regenerator.wrap方法包裹,用于捕获effect生成器函数调用时的报错
        return _regenerator2.default.wrap(function sagaWithCatch$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              // sagaWithCatch()返回值首次执行next方法时,调用innerFn即sagaWithCatch的case 0条件分支语句
              case 0:
                _context4.prev = 0;

                for (_len = _args4.length, args = Array(_len), _key = 0; _key < _len; _key++) {
                  args[_key] = _args4[_key];
                }

                _context4.next = 4;

                // 用户配置的model.effects生成器函数实际获得的参数为args和封装put方法后的sagaEffects对象
                // createEffects(model)函数获取put方法经封装后的sagaEffects对象
                // 其put方法输出extend(action,{type:prefixType(type,model)}),即action.type添加model.namespace+"/"前缀
                return effect.apply(undefined, 
                    (0, _toConsumableArray3.default)(args.concat(createEffects(model)))
                  );

              // sagaWithCatch()返回值二次执行next方法时,调用innerFn即sagaWithCatch$的case 4条件分支语句
              case 4:
                _context4.next = 9;
                break;

              // 由regenerator.wrap方法的第四个参数设定,报错时调用innerFn即sagaWithCatch$的case 6条件分支语句
              case 6:
                _context4.prev = 6;
                // context['catch'](0),按regenrator-runtime机制,为innerFn即sagaWithCatch$执行case 0时捕获的错误
                _context4.t0 = _context4['catch'](0);

                onError(_context4.t0);

              // sagaWithCatch()返回值三次执行next方法时,调用innerFn即sagaWithCatch$的case 9条件分支语句
              // 即sagaWithCatch类生成器函数执行完毕
              case 9:
              case 'end':
                return _context4.stop();
            }
          }
        }, _marked[0], this, [[0, 6]]);// [[0, 6]]决定innerFn即sagaWithCatch$的条件语句执行机制
      }

      // 获取dva.use("onEffect",fn)注册的函数fn(effect,sagaEffects,model,key)装饰model.effects中各生成器函数
      var onEffect = plugin.get('onEffect');
      var sagaWithOnEffect = applyOnEffect(onEffect, sagaWithCatch, model, key);

      switch (type) {
        case 'watcher':
          // 返回sagaWithCatch,调用sagaWithCatch函数创建生成器,next方法执行effect生成器函数
          return sagaWithCatch;
        case 'takeLatest':
          return _regenerator2.default.mark(function _callee4() {
            return _regenerator2.default.wrap(function _callee4$(_context5) {
              while (1) {
                switch (_context5.prev = _context5.next) {
                  case 0:
                    _context5.next = 2;
                    return (0, _sagaHelpers.takeLatestHelper)(key, sagaWithOnEffect);

                  case 2:
                  case 'end':
                    return _context5.stop();
                }
              }
            }, _callee4, this);
          });
        case 'throttle':
          return _regenerator2.default.mark(function _callee5() {
            return _regenerator2.default.wrap(function _callee5$(_context6) {
              while (1) {
                switch (_context6.prev = _context6.next) {
                  case 0:
                    _context6.next = 2;
                    return (0, _sagaHelpers.throttleHelper)(ms, key, sagaWithOnEffect);

                  case 2:
                  case 'end':
                    return _context6.stop();
                }
              }
            }, _callee5, this);
          });
        default:
          // 返回值为generator生成器函数,执行后获取含有next方法的生成器函数相关迭代器
          // next方法首次执行返回sagaHelpers.takeEveryHelper方法封装的迭代器函数
          // next方法再次执行意味generator生成器函数执行完毕
          return _regenerator2.default.mark(function _callee6() {
            return _regenerator2.default.wrap(function _callee6$(_context7) {
              while (1) {
                switch (_context7.prev = _context7.next) {
                  // _callee6()返回值首次执行next方法时,调用innerFn即_callee6$的case 0条件分支语句
                  case 0:
                    _context7.next = 2;
                    // sagaHelpers.takeEveryHelper方法执行返回迭代器
                    // 返回值迭代器的next方法首次执行,设定将根据二次调用next方法的参数时更改action值
                    // next方法再次执行,更改action,并返回{context:null,fn:sagaWithOnEffect,args:action}
                    return (0, _sagaHelpers.takeEveryHelper)(key, sagaWithOnEffect);

                  // _callee6()返回值二次执行next方法时,调用innerFn即_callee6$的case 2条件分支语句
                  // 即_callee6类生成器函数执行完毕
                  case 2:
                  case 'end':
                    return _context7.stop();
                }
              }
            }, _callee6, this);
          });
      }
    }

    // 组件渲染完成当即执行model.subscription中各方法,派发action,返回解绑函数集合
    function runSubscriptions(subs, model, app, onError) {
      var unlisteners = [];
      var noneFunctionSubscriptions = [];
      for (var key in subs) {
        if (Object.prototype.hasOwnProperty.call(subs, key)) {
          var sub = subs[key];
          // 校验model.subscription对象的属性值为函数
          (0, _invariant2.default)(typeof sub === 'function', 
            'app.start: subscription should be function');
          var unlistener = sub({
            dispatch: createDispatch(app._store.dispatch, model),
            history: app._history
          }, onError);
          if ((0, _lodash2.default)(unlistener)) {
            unlisteners.push(unlistener);
          } else {
            noneFunctionSubscriptions.push(key);
          }
        }
      }
      return { unlisteners: unlisteners, noneFunctionSubscriptions: noneFunctionSubscriptions };
    }

    // model.reducers或model.effects存在时,type拼接上model.namespace+"/"前缀后返回
    function prefixType(type, model) {
      var prefixedType = '' + model.namespace + SEP + type;
      if (model.reducers && model.reducers[prefixedType] || model.effects && model.effects[prefixedType]) {
        return prefixedType;
      }
      return type;
    }

    // 获取put方法经封装后的sagaEffects对象,put方法输出extend(action,{type:prefixType(type,model)})
    // 即action.type经model.namespace+"/"前缀后
    function createEffects(model) {
      function put(action) {
        var type = action.type;

        // 校验action.type属性必须为真值,且不能以model.namespace+"/"起始
        (0, _invariant2.default)(type, 'dispatch: action should be a plain Object with type');
        (0, _warning2.default)(type.indexOf('' + model.namespace + SEP) !== 0, 
          'effects.put: ' + type + ' should not be prefixed with namespace ' + model.namespace);

        return sagaEffects.put((0, _extends3.default)({}, action, { type: prefixType(type, model) }));
      }
      return (0, _extends3.default)({}, sagaEffects, { put: put });
    }

    // 调用redux的dispatch方法派发action
    function createDispatch(dispatch, model) {
      return function (action) {
        var type = action.type;

        // 校验action.type属性必须为真值,且不能以model.namespace+"/"起始
        (0, _invariant2.default)(type, 'dispatch: action should be a plain Object with type');
        (0, _warning2.default)(type.indexOf('' + model.namespace + SEP) !== 0, 
          'dispatch: ' + type + ' should not be prefixed with namespace ' + model.namespace);
        return dispatch((0, _extends3.default)({}, action, { type: prefixType(type, model) }));
      };
    }

    // 装饰model.effects中各生成器函数
    // dva.use("onEffect",fn)方法注册的函数fn(effect,sagaEffects,model,key)用于装饰model.effects中各生成器函数
    function applyOnEffect(fns, effect, model, key) {
      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = (0, _getIterator3.default)(fns), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var fn = _step5.value;

          effect = fn(effect, sagaEffects, model, key);
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5.return) {
            _iterator5.return();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }

      return effect;
    }
  };
}
module.exports = exports['default'];

 

lib/handleActions.js流程控制,通过参数action.type调用相应的reducer

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _toConsumableArray2 = require("babel-runtime/helpers/toConsumableArray");
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _keys = require("babel-runtime/core-js/object/keys");
var _keys2 = _interopRequireDefault(_keys);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function identify(value) {
  return value;
}

function handleAction(actionType) {
  var reducer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : identify;

  return function (state, action) {
    var type = action.type;

    if (type && actionType !== type) {
      return state;
    }
    return reducer(state, action);
  };
}

function reduceReducers() {
  for (var _len = arguments.length, reducers = Array(_len), _key = 0; _key < _len; _key++) {
    reducers[_key] = arguments[_key];
  }

  return function (previous, current) {
    return reducers.reduce(function (p, r) {
      return r(p, current);
    }, previous);
  };
}

// 参数handlers={actionType:reducer(state,action)=>{}}
// 流程控制,按返回函数的传参action.type执行相应的reducer,修改state
function handleActions(handlers, defaultState) {
  // 获取[(state,action)=>{}]函数集合
  // 当action.type与actionType相符时,执行相应的reducer,修改state后,作为参数传入下一个(state,action)=>{}函数
  // 不符时,直接将state作为参数传入下一个(state,action)=>{}函数
  var reducers = (0, _keys2.default)(handlers).map(function (type) {
    return handleAction(type, handlers[type]);
  });

  // 流程控制,按action.type执行相应的reducer,修改state;或跳过reducer执行,将state传递到下一个流程
  var reducer = reduceReducers.apply(undefined, (0, _toConsumableArray3.default)(reducers));

  // 按action.type执行相应的reducer,修改state
  return function () {
    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState;
    var action = arguments[1];
    return reducer(state, action);
  };
}

exports.default = handleActions;
module.exports = exports["default"];

 

lib/plugin.js插件机制,用于设定钩子

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);

var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);

var _isPlainObject = require('is-plain-object');
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);

var _invariant = require('invariant');
var _invariant2 = _interopRequireDefault(_invariant);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var Plugin = function () {
  function Plugin() {
    (0, _classCallCheck3.default)(this, Plugin);

    this.hooks = {
      onError: [],
      onStateChange: [],
      onAction: [],
      onHmr: [],
      onReducer: [],
      onEffect: [],
      extraReducers: [],
      extraEnhancers: []
    };
  }

  // plugin.use(plugin={key:fn})添加钩子函数,存入this.hooks中
  // 当key为'extraEnhancers',钩子为单函数形式;当key为其他时,钩子为数组形式
  (0, _createClass3.default)(Plugin, [{
    key: 'use',
    value: function use(plugin) {
      // 校验plugin位普通对象
      (0, _invariant2.default)((0, _isPlainObject2.default)(plugin), 
        'plugin.use: plugin should be plain object');
      var hooks = this.hooks;
      for (var key in plugin) {
        if (Object.prototype.hasOwnProperty.call(plugin, key)) {
          (0, _invariant2.default)(hooks[key], 'plugin.use: unknown plugin property: ' + key);
          if (key === 'extraEnhancers') {
            hooks[key] = plugin[key];
          } else {
            hooks[key].push(plugin[key]);
          }
        }
      }
    }

  // plugin.apple("onError | onHmr",defaultHandler)以迭代器调用数组形式的"onError | onHmr"钩子函数集合
  // 若不存在this.hooks["onError | onHmr"],调用defaultHandler函数
  }, {
    key: 'apply',
    value: function apply(key, defaultHandler) {
      var hooks = this.hooks;
      var validApplyHooks = ['onError', 'onHmr'];
      (0, _invariant2.default)(validApplyHooks.indexOf(key) > -1, 
        'plugin.apply: hook ' + key + ' cannot be applied');
      var fns = hooks[key];

      return function () {
        if (fns.length) {
          var _iteratorNormalCompletion = true;
          var _didIteratorError = false;
          var _iteratorError = undefined;

          try {
            for (var _iterator = (0, _getIterator3.default)(fns), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
              var fn = _step.value;

              fn.apply(undefined, arguments);
            }
          } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion && _iterator.return) {
                _iterator.return();
              }
            } finally {
              if (_didIteratorError) {
                throw _iteratorError;
              }
            }
          }
        } else if (defaultHandler) {
          defaultHandler.apply(undefined, arguments);
        }
      };
    }

  // 获取添加的钩子,通常返回plugin.hooks[key]
  // 当key为'extraReducers'时,plugin.hooks.extraReducers=[{actionType:()=>{}}]从数组转化为对象后输出
  // 当key为'onReducer'时,plugin.hooks.onReducer=[fn]从数组转化为逐次调用fn的函数,用于装饰redux.combineReducers返回值
  }, {
    key: 'get',
    value: function get(key) {
      var hooks = this.hooks;
      (0, _invariant2.default)(key in hooks, 'plugin.get: hook ' + key + ' cannot be got');
      if (key === 'extraReducers') {
        var ret = {};
        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;

        try {
          for (var _iterator2 = (0, _getIterator3.default)(hooks[key]), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
            var reducerObj = _step2.value;

            ret = (0, _extends3.default)({}, ret, reducerObj);
          }
        } catch (err) {
          _didIteratorError2 = true;
          _iteratorError2 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion2 && _iterator2.return) {
              _iterator2.return();
            }
          } finally {
            if (_didIteratorError2) {
              throw _iteratorError2;
            }
          }
        }

        return ret;
      } else if (key === 'onReducer') {
        return function (reducer) {
          var _iteratorNormalCompletion3 = true;
          var _didIteratorError3 = false;
          var _iteratorError3 = undefined;

          try {
            for (var _iterator3 = (0, _getIterator3.default)(hooks[key]), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
              var reducerEnhancer = _step3.value;

              reducer = reducerEnhancer(reducer);
            }
          } catch (err) {
            _didIteratorError3 = true;
            _iteratorError3 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion3 && _iterator3.return) {
                _iterator3.return();
              }
            } finally {
              if (_didIteratorError3) {
                throw _iteratorError3;
              }
            }
          }

          return reducer;
        };
      } else {
        return hooks[key];
      }
    }
  }]);
  return Plugin;
}();

exports.default = Plugin;
module.exports = exports['default'];

 

lib/mobile.js

'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createDva = require('./createDva');
var _createDva2 = _interopRequireDefault(_createDva);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.default = (0, _createDva2.default)({
  mobile: true
});
module.exports = exports['default'];

 

0
0
分享到:
评论

相关推荐

    umi3+dva编程学习资源,自用

    umi3+dva编程学习资源,自用 umi3 和 dva 是两个相关的概念,umi3 是一个基于 React 的前端框架,而 dva 是一个基于 Redux 和 Redux-saga 的数据流方案。在本文中,我们将详细介绍 dva 的概念和使用方法,以及如何...

    AWS DVA-C02样题

    【AWS DVA-C02样题】是针对亚马逊AWS Certified Developer - Associate认证考试的一个学习资源。这个认证旨在验证开发者在使用Amazon Web Services (AWS) 构建和部署应用程序的能力。DVA-C02考试主要涵盖了以下几个...

    dva API.pdf

    ### dva API 概述 #### 一、dva API框架简介 dva是一个轻量级的前端应用开发框架,它基于Redux,并对其进行了高度封装,使得开发者能够更轻松地构建复杂的前端应用。dva的核心设计理念是简化开发流程,通过减少...

    AWS Developer Associate DVA-C01 Lead2Pass pdf.rar

    AWS Developer Associate DVA-C01认证是亚马逊网络服务(Amazon Web Services, AWS)为开发者提供的一项专业认证,旨在验证考生在使用AWS云平台进行应用程序开发方面的技能和知识。这个认证适用于那些希望展示自己在...

    dva快速入门附件

    ### DVA快速入门知识点解析 #### 一、DVA框架简介 DVA 是一个基于 Redux、Redux-Saga 和 React 的轻量级应用框架,它简化了应用开发过程中的状态管理和组件间通信。DVA 通过 Model 的概念来组织代码,使得开发者...

    dva-demo.zip

    【标题】"dva-demo.zip" 是一个包含使用React框架集成DVA库的示例项目的压缩包。这个项目提供了一个实际操作的环境,让你能够学习和理解如何在React应用中运用DVA进行状态管理和数据流控制。DVA是基于Redux和Redux-...

    dva-admin-demo.7z

    【标题】"dva-admin-demo.7z" 是一个基于DVA框架构建的后台管理系统示例项目,压缩包内包含了整个项目的源代码。DVA是一个轻量级的JavaScript状态管理库,它基于React和Redux,并集成了Redux-Saga用于处理异步逻辑。...

    开箱即用的dva框架

    【标题】"开箱即用的dva框架"揭示了我们正在讨论的是一款基于DVA构建的前端开发框架,它特别强调的是其易用性和快速启动项目的能力。DVA是基于React和Redux的一个轻量级状态管理框架,设计初衷是为了简化复杂的前端...

    基于React和Dva的大数据可视化大屏展示模板设计源码

    本设计源码提供了一个基于React和Dva的大数据可视化大屏展示模板,包含64个文件,其中包括30个js脚本文件,9张png图片,8个jsx文件,3个json数据文件,以及1个editorconfig文件,1个eslintrc文件,1个gitignore文件...

    dva新手综合教程

    【dva新手综合教程】 本教程旨在为初学者提供一个全面了解和学习dva的平台。Dva是一款基于React和Redux的小型轻量级前端框架,它将React、Redux、React Router以及 Saga 等优秀库整合在一起,使得前端开发更为高效...

    taro配合dva的实践

    在现代前端开发中,Taro 和 DVA 是两个非常受欢迎的框架。Taro 是一个开源的多端开发框架,允许开发者用 React 的开发方式编写代码,同时可以编译到微信小程序、H5、React Native 等多个平台。DVA 是基于蚂蚁金服的 ...

    create-react-app构建dva项目20180728

    在本项目中,"create-react-app构建dva项目20180728",开发者采用了一种现代化的前端开发方式,结合了create-react-app、dva和antd等技术栈,来创建一个功能完善的音乐模块。create-react-app是Facebook推出的一个...

    AWS Certified Developer Associate (DVA-C02)- 认证考试题库-英文-系列一.pdf

    AWS Certified Developer Associate (DVA-C02) 是一项针对AWS开发者的认证考试,旨在验证候选人在AWS云环境中构建和维护应用程序的能力。这份题库资源包含了50道免费试题,涵盖高频题和完整的试题集,旨在帮助考生...

    dva-boilerplate-electron, 另一个dva样板.zip

    dva-boilerplate-electron, 另一个dva样板 dva-boilerplate-electron使用电子和 dva创建一个应用程序的样板。正在启动在你的目录中,运行:$ curl -fsSL https://github.com/sorrycc/dva-boilerpla

    一个基于dva的脚手架

    **基于DVA的脚手架详解** DVA是一款轻量级的前端框架,它结合了React、Redux和 Saga,使得在构建复杂的JavaScript应用时能够更加高效和简洁。DVA这个名字来源于“模型驱动开发”(Model Driven Development)的首...

    基于React、Dva、ECharts、DataV的框架大数据可视化(大屏展示)模板

    基于React、Dva、ECharts以及DataV的框架,为大数据可视化提供了强大的解决方案,特别是针对大屏展示的设计。本模板就是这样一个工具,旨在简化开发过程,提供丰富的功能和高度的定制性。 React是Facebook推出的一...

    基于dva和immutablejs的model创建工具

    在IT行业中,JavaScript是一种广泛应用的前端开发语言,而dva和immutable.js是两个非常重要的库,它们在构建高效、可维护的React应用中扮演着关键角色。本文将深入探讨这两个库以及如何结合它们来创建一个基于model...

    dva+mockjs实现模拟请求

    这就是`Mock.js`和`dva`框架结合使用的场景。本文将详细介绍如何在`dva`项目中利用`Mock.js`实现模拟请求,以及涉及到的相关技术。 首先,`dva`是一个基于`React`和`Redux`的轻量级应用框架,它简化了状态管理和...

    德莱尔DVA系列变频器使用说明书.pdf

    德莱尔DVA系列变频器是高性能通用型变频器产品,它在工业应用中广泛用于电机速度控制,能够有效实现对电机启动、加速、减速及停止的准确控制。使用说明书中涵盖了变频器的安装、参数设定、异常诊断、排除故障以及...

    create-react-app构建dva项目20180724

    在本文中,我们将深入探讨如何使用`create-react-app`创建一个基于DVA的React项目,并解决其中的路由问题。`create-react-app`是Facebook提供的一个官方工具,它可以帮助开发者快速搭建React应用,无需关注配置,...

Global site tag (gtag.js) - Google Analytics