最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • dva中的subscriptions应该这么用

    正文概述 掘金(无束)   2021-02-05   478

    欢迎关注公众号【码上出击】,更多精彩内容敬请关注公众号最新消息。

    demo地址

    Q:dva中的 subscriptions 到底是干嘛用的。
    A:如果你需要订阅一些数据,并且处理数据后的逻辑仅与当前model相关,那么就应该用 subscriptions 。

    官方文档对于subscriptions的描述太简单了,以致很多同学对这个概念不是很清楚。

    dva中的subscriptions应该这么用

    1. 代码分析

    从源码中摘取出来了与subscription有关的关键代码如下:

    // index.js
    
    import { run as runSubscription, unlisten as unlistenSubscription } from './subscription';
    
    /**
     * Create dva-core instance.
     */
    export function create(hooksAndOpts = {}, createOpts = {}) {
      // ......
      
      const app = {
        _models: [prefixNamespace({ ...dvaModel })],
        _store: null,
        _plugin: plugin,
        use: plugin.use.bind(plugin),
        model,
        start,
      };
      return app;
      
      // ......
      
      /**
       * Register model before app is started.
       */
      function model(m) {
        if (process.env.NODE_ENV !== 'production') {
          checkModel(m, app._models);
        }
        const prefixedModel = prefixNamespace({ ...m });
        app._models.push(prefixedModel);
        return prefixedModel;
      }
    
      /**
       * Inject model after app is started.
       */
      function injectModel(createReducer, onError, unlisteners, m) {
        m = model(m);
    
        const store = app._store;
        store.asyncReducers[m.namespace] = getReducer(m.reducers, m.state, plugin._handleActions);
        store.replaceReducer(createReducer());
        if (m.effects) {
          store.runSaga(app._getSaga(m.effects, m, onError, plugin.get('onEffect'), hooksAndOpts));
        }
        if (m.subscriptions) {
          unlisteners[m.namespace] = runSubscription(m.subscriptions, m, app, onError);
        }
      }
    
      /**
       * Unregister model.
       */
      function unmodel(createReducer, reducers, unlisteners, namespace) {
        const store = app._store;
    
        // Delete reducers
        delete store.asyncReducers[namespace];
        delete reducers[namespace];
        store.replaceReducer(createReducer());
        store.dispatch({ type: '@@dva/UPDATE' });
    
        // Cancel effects
        store.dispatch({ type: `${namespace}/@@CANCEL_EFFECTS` });
    
        // Unlisten subscrioptions
        unlistenSubscription(unlisteners, namespace);
    
        // Delete model from app._models
        app._models = app._models.filter(model => model.namespace !== namespace);
      }
    
      /**
       * Start the app.
       *
       * @returns void
       */
      function start() {
        // ......
    
        // Run subscriptions
        const unlisteners = {};
        for (const model of this._models) {
          if (model.subscriptions) {
            unlisteners[model.namespace] = runSubscription(model.subscriptions, model, app, onError);
          }
        }
    
        // Setup app.model and app.unmodel
        app.model = injectModel.bind(app, createReducer, onError, unlisteners);
        app.unmodel = unmodel.bind(app, createReducer, reducers, unlisteners);
        app.replaceModel = replaceModel.bind(app, createReducer, reducers, unlisteners, onError);
    
        // ......
      }
    }
    
    // subscription.js
    
    export function run(subs, model, app, onError) {
      const funcs = [];
      const nonFuncs = [];
      for (const key in subs) {
        if (Object.prototype.hasOwnProperty.call(subs, key)) {
          const sub = subs[key];
          const unlistener = sub(
            {
              dispatch: prefixedDispatch(app._store.dispatch, model),
              history: app._history,
            },
            onError,
          );
          if (isFunction(unlistener)) {
            funcs.push(unlistener);
          } else {
            nonFuncs.push(key);
          }
        }
      }
      return { funcs, nonFuncs };
    }
    

    run方法做的事情就是把model中配置的 subscriptions 遍历执行,并且将dispatch方法和history对象做为参数传给配置的每一个subscription。

    从代码上我们可以看到,start方法执行时,会将app.model注册进来的所有model.subscriptions 遍历执行,并且将执行后的返回值收集到了 unlisteners[model.namespace] 中,供 app.unmodel(namespace) 时取消订阅数据源用。

    // Run subscriptions
    const unlisteners = {};
    for (const model of this._models) {
      if (model.subscriptions) {
        unlisteners[model.namespace] = runSubscription(model.subscriptions, model, app, onError);
      }
    }
    

    另外,在 subscription.js 中的 run 方法中,将 prefixedDispatch(app._store.dispatch, model) 做为 dispatch 传给了 subscription 配置的方法,精简后的代码如下:

    function prefixedDispatch(dispatch, model){
    	return action => {
          app._store.dispatch({
            ...action, 
            type: `${model.namespace}${NAMESPACE_SEP}${action.type}`
          })
        }
    }
    

    因此,可以看出,在 subscriptions 中,只能 dispatch 当前 model 中的 reducer 和 effects 。

    2. 结论

    从代码中我么可以得出以下结论:

    1. subscriptions 中配置的key的名称没有任何约束,而且只有在app.unmodel的时候才有用。
    2. subscriptions 中配置的只能dispatch所在model的reducer和effects。
    3. subscriptions 中配置的函数只会执行一次,也就是在调用 app.start() 的时候,会遍历所有 model 中的 subscriptions 执行一遍。
    4. subscriptions 中配置的函数需要返回一个函数,该函数应该用来取消订阅的该数据源。

    3. 代码示例

    // models/Products.js
    
    export default {
      namespace: 'products',
      
      // ......
      
      subscriptions: {
        setupxxx({ dispatch, history }) {
          // history.listen执行后会返回unlisten函数
          return history.listen(({ pathname, query }) => {
            console.log('history')
          });
        },
        i_am_just_a_name({dispatch}){
          console.log('into')
          
          function handleClick() {
            console.log('hello')
            dispatch({
              type: 'delete',
              payload: 1
            })
          }
          document.addEventListener('click', handleClick);
    
          // 此处返回一个函数,用来移除click事件
          return () => {
            document.removeEventListener('click', handleClick)
          }
        }
      },
    	
      // ......
    };
    
    

    起源地下载网 » dva中的subscriptions应该这么用

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元