亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

dva源碼解析(一)

bladefury / 1100人閱讀

摘要:動(dòng)態(tài)處理與,封裝了在運(yùn)行時(shí)的進(jìn)行一類增加和刪除的操作,例如可以再切換到某一路由時(shí)動(dòng)態(tài)的加入一個(gè)個(gè)人猜測(cè),熱更新很有可能也利用了這個(gè)兩個(gè)與。以上是本人對(duì)于的粗略的理解,內(nèi)容如有錯(cuò)誤,還請(qǐng)大家指出。

寫在前面

dva是螞蟻金服推出的一個(gè)單頁應(yīng)用框架,對(duì)reduxreact-router,redux-saga進(jìn)行了上層封裝,沒有引入新的概念,但是極大的程度上提升了開發(fā)效率;下面內(nèi)容為本人理解,如有錯(cuò)誤,還請(qǐng)指出,不勝感激。

redux的痛苦

redux的優(yōu)點(diǎn)很多,痛點(diǎn)也有,比如異步控制,redux-saga的出現(xiàn)使得異步操作變得優(yōu)雅,但是基于redux-saga不得不承認(rèn)的一點(diǎn)就是開發(fā)過程實(shí)在是太麻煩了,假若增加一個(gè)操作,不得不操作actions,reducers,sagas,對(duì)于sagas可以還需要進(jìn)行watch,而后還要進(jìn)行fork;(PS: 本來就夠麻煩了,再加上一個(gè)sagas);在添加一個(gè)操作時(shí),不得不操作這么多的文件,實(shí)在是麻煩,而dva的出現(xiàn)在一定程度上解決了這個(gè)問題。

dva基本概念

未使用dva下的目錄經(jīng)常是這樣的:

actions
   --/ user.js
   --/ team.js
reducers
   --/ user.js
   --/ team.js
sagas/
   --/ user.js
   --/ team.js

dva將其合并:

models
   --/ user.js
   --/ team.js

dva中有著幾個(gè)概念:

namespace       =>  combineReducers中對(duì)應(yīng)的key值
state           =>  對(duì)應(yīng)初始的state,也就是initialState
effects         =>  saga的處理函數(shù)
reducers        =>  對(duì)應(yīng)reducers,不同的是,寫法上將switch...case轉(zhuǎn)化為對(duì)象  

除了這些以外,dva中還有subscriptions,這一概念來源于elm,

dva的實(shí)現(xiàn) 初始化
const app = dva({
    history: browserHistory
});

上面的過程發(fā)生了什么?
dva本質(zhì)上調(diào)用了下面函數(shù):

function dva(hooks = {}) {
    const history = hooks.history || defaultHistory;
    const initialState = hooks.initialState || {};
    delete hooks.history;
    delete hooks.initialState;

    const plugin = new Plugin();
    plugin.use(hooks);

    const app = {
      // properties
      _models: [],
      _router: null,
      _store: null,
      _history: null,
      _plugin: plugin,
      _getProvider: null,
      // methods
      use,
      model,
      router,
      start,
    };
    return app;
}

hooks為傳入的一些配置,例如可以通過傳入history來改變路由的實(shí)現(xiàn),dva默認(rèn)采用的是hashHistory;從這里可以看出dva暴露出來的方法:

app.router():指定路由,需要傳入一個(gè)函數(shù),一般類似于({ history }) => (...)

app.use():添加插件,這個(gè)稍后來看~

app.model():添加model,也就是對(duì)應(yīng)的添加一個(gè)store下的數(shù)據(jù),該方法做的就是對(duì)傳入的model進(jìn)行檢查,對(duì)reducers添加命名空間,而后將其push_models中。

namespace必須且唯一,因?yàn)閮?nèi)置了react-redux-router,所以namespace也不能為routing

subscriptionseffects均為可選參數(shù),傳入的話必須為對(duì)象

reducers為可選,支持對(duì)象和數(shù)組兩種傳入方式(傳入數(shù)組的方式,往往伴隨著高階reducer的應(yīng)用,具體稍后再看~)

app.start():初始化應(yīng)用,接受參數(shù)為選擇器或者DOM節(jié)點(diǎn)

需要注意的是:

reducerseffectskey不需要用namespace/action的形式了,因?yàn)?b>dva會(huì)自動(dòng)將其加上,dispatch的時(shí)候,saga需要加上namespace,而saga中的put不需要加入namespace,原因是dva對(duì)put進(jìn)行了重載

dva同時(shí)支持rn應(yīng)用,引入dva/mobile即可,這時(shí)react-router不在需要,利用rn中的Navigator即可,不會(huì)引用react-routerreact-redux-routernamespace可以命名為routing;正是由于這點(diǎn)差異,作者將路由相關(guān)的內(nèi)容作為參數(shù)傳入了進(jìn)去,具體可以參見這個(gè)文件。

創(chuàng)建

將一些配置項(xiàng)初始化好后,就可以app.start就是來創(chuàng)建一個(gè)應(yīng)用,下面就一點(diǎn)點(diǎn)的看看start的過程(以下基于默認(rèn)情況,也就是使用了react-router):

參數(shù)校驗(yàn),是否為DOM元素或者檢查是否可以根據(jù)傳入的選擇器字符串找到對(duì)應(yīng)的DOM,這個(gè)DOM對(duì)應(yīng)的就是ReactDOM.render的第二個(gè)參數(shù)。

錯(cuò)誤處理,使得發(fā)生錯(cuò)誤時(shí),不至于應(yīng)用奔潰,當(dāng)然需要傳入自定義hooks.onError來處理:

  // 傳入hooks.onError則調(diào)用,反之調(diào)用默認(rèn)函數(shù)處理,拋出異常即可
  const onError = plugin.apply("onError", (err) => {
    throw new Error(err.stack || err);
  });
  // 目的是出現(xiàn)錯(cuò)誤時(shí),也可以進(jìn)行dispatch操作
  const onErrorWrapper = (err) => {
    if (err) {
      if (typeof err === "string") err = new Error(err);
      onError(err, app._store.dispatch);
    }
  };

遍歷_models,初始化reducers,sagas

const sagas = [];
// initalReducer為{ routing: routerReducer }
const reducers = { ...initialReducer };  // 為rootReducer
for (const m of this._models) {
    // 得到默認(rèn)的state
    reducers[m.namespace] = getReducer(m.reducers, m.state);
    if (m.effects) sagas.push(getSaga(m.effects, m, onErrorWrapper));
}
處理reducers

對(duì)于reduxreducers最常見的是基于switch..case的,而dva做出了一些改變,將每一個(gè)case分支變作了一個(gè)函數(shù):

(PS: 本人認(rèn)為,這個(gè)可以塊可以更改,利用some操作來盡可能少的調(diào)用無意義的reducer,于是我提了一個(gè)pr)

每一個(gè)reducer的實(shí)現(xiàn)如下:

// actionType對(duì)應(yīng)的是dva的reducers中的key值
(state, action) => {
    const { type } = action;
    if (type && actionType !== type) {
        return state;
    }
    return reducer(state, action);
};
處理sagas

看完了對(duì)于reducers的處理,下面來看一下對(duì)于sagas的處理:

function getSaga(effects, model, onError) {
  return function *() {
    for (const key in effects) {
      if (Object.prototype.hasOwnProperty.call(effects, key)) {
        const watcher = getWatcher(key, effects[key], model, onError);
        const task = yield sagaEffects.fork(watcher);
        // 為了移除時(shí)可以將saga任務(wù)注銷
        yield sagaEffects.fork(function *() {
          yield sagaEffects.take(`${model.namespace}/@@CANCEL_EFFECTS`);
          yield sagaEffects.cancel(task);
        });
      }
    }
  };
}

getWatcher返回一個(gè)saga監(jiān)聽函數(shù),也就是通常寫的watchXXXmodel.effects[key]可以是一個(gè)任務(wù)函數(shù);也可以是個(gè)數(shù)組,第一個(gè)參數(shù)為任務(wù)函數(shù),第二為配置對(duì)象,可以傳入type,type有4個(gè)可選值,takeEvery(默認(rèn)),takeLatest,throttle,watcher四種,dva對(duì)effects做了一個(gè)錯(cuò)誤處理:

effect => function *(...args) {
  try {
    yield effect(...args.concat(createEffects(model)));
  } catch (e) {
    onError(e);   // 為之前的onErrorWrapper
  }
}

注意:

watcher是指?jìng)魅氲娜蝿?wù)函數(shù)就是一個(gè)watcher直接fork就好

throttle還要傳入一個(gè)ms配置,這個(gè)ms代表著在多少毫秒內(nèi)只觸發(fā)一次同一類型saga任務(wù),而takeEvery是不會(huì)限制同一類型執(zhí)行次數(shù),takeLatest只能執(zhí)行一個(gè)同一類型任務(wù),有執(zhí)行中的再次執(zhí)行就會(huì)取消

getSaga可以看出,${namespace}/@@CANCEL_EFFECTS可以取消對(duì)應(yīng)的任務(wù)監(jiān)聽

可以通過配置hooks.onEffect來增加sagawatcher

增強(qiáng)redux

redux中間件,由sagaMiddware,routerMiddware(啟用react-router時(shí)),hooks.onAction傳入的其它中間件,如redux-logger

其它增強(qiáng),如redux-devtools,內(nèi)置了redux-devtools,另需的話在hooks.extraReducers傳入

  const enhancers = [
    applyMiddleware(...middlewares),
    devtools(),
    ...extraEnhancers,
  ];
  const store = this._store = createStore(  // eslint-disable-line
    createReducer(),
    initialState,
    compose(...enhancers),
  );
設(shè)置redux的回調(diào)函數(shù)

通過配置hooks.onStateChange可以指定reduxstate改變后所觸發(fā)的回調(diào)函數(shù):

const listeners = plugin.get("onStateChange");
  for (const listener of listeners) {
    store.subscribe(() => {
      listener(store.getState());
    });
  }
}
新概念subscriptions

subscriptions是一個(gè)新概念,會(huì)在dom ready之后執(zhí)行,在這里面可以做一些基礎(chǔ)數(shù)據(jù)的獲?。?br>一般會(huì)將初始數(shù)據(jù)的獲取放在react的生命周期中,比如componentWillMount,但是假設(shè)我們做了代碼分割,實(shí)現(xiàn)了按需加載,那么我們開始獲取數(shù)據(jù)的時(shí)間為:獲取相應(yīng)的js+解析js+執(zhí)行react生命周期,但是redux的數(shù)據(jù)加載和ui組件沒有太大關(guān)系,可以將數(shù)據(jù)獲取的時(shí)間點(diǎn)提前,subscriptions提供了解決方法,其意義為訂閱,對(duì)于上面的場(chǎng)景,我們可以訂閱路由,到了執(zhí)行的路由執(zhí)行相應(yīng)的dispatch(),如:

setup({ dispatch, history }) {
  return history.listen(({ pathname, query }) => {
    if (pathname === "/users") {
      dispatch({ type: "fetch", payload: query });
    }
  });
}

(PS: 對(duì)于這個(gè)新概念,我也不是很清楚,后面的文章會(huì)有專門的描述,大家先有一個(gè)概念就好)

掛載

上述過程均為初始化的過程,就是獲取到需要的reducers,sagas以及對(duì)于一些中間件和插件的配置,下面要進(jìn)行的就是掛載了,也就熟悉的render(, container)

動(dòng)態(tài)處理model

dva.modeldva.unmodel,封裝了在運(yùn)行時(shí)的store進(jìn)行一類增加和刪除的操作,例如可以再切換到某一路由時(shí)動(dòng)態(tài)的加入一個(gè)model(個(gè)人猜測(cè),熱更新很有可能也利用了這個(gè)兩個(gè)apihooks.onHmr)。

未完結(jié)

關(guān)于redux還有一個(gè)利器,那就是高階reduce,當(dāng)然在dva中也有體現(xiàn),這篇文章已經(jīng)很長(zhǎng)了,這些內(nèi)容留在下一篇中介紹。以上是本人對(duì)于dva的粗略的理解,內(nèi)容如有錯(cuò)誤,還請(qǐng)大家指出。dva的確簡(jiǎn)化了開發(fā)的流程,而且在螞蟻金服的很多業(yè)務(wù)線也有著應(yīng)用,是一個(gè)很值得大家一試!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/83474.html

相關(guān)文章

  • dva系列源碼解讀

    摘要:介紹概述本次對(duì)源碼的解讀除了傳統(tǒng)的從入手外還將引入帶入問題讀源碼的理念,因?yàn)橹挥羞@樣當(dāng)讀完源碼之后才會(huì)有切身的收獲。 介紹 概述 本次對(duì) dva 源碼的解讀除了傳統(tǒng)的從 api 入手外還將引入帶入問題讀源碼的理念,因?yàn)橹挥羞@樣當(dāng)讀完源碼之后才會(huì)有切身的收獲。另外除了 dva 的源碼外還會(huì)解讀一些常用的 dva 插件的源碼。 電子書 https://dva-source-docs.net...

    focusj 評(píng)論0 收藏0
  • React生態(tài),dva源碼閱讀

    摘要:下面會(huì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁面后,每一個(gè)子頁面對(duì)應(yīng)一個(gè)文件??偨Y(jié)上面就是最早版本的源碼,很簡(jiǎn)潔的使用了等其目的也很簡(jiǎn)單簡(jiǎn)化相關(guān)生態(tài)的繁瑣邏輯參考源碼地址 ??dva的思想還是很不錯(cuò)的,大大提升了開發(fā)效率,dva集成了Redux以及Redux的中間件Redux-saga,以及React-router等等。得益于Redux的狀態(tài)管理,以及Redux-saga中...

    bergwhite 評(píng)論0 收藏0
  • React生態(tài),dva源碼閱讀

    摘要:下面會(huì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁面后,每一個(gè)子頁面對(duì)應(yīng)一個(gè)文件??偨Y(jié)上面就是最早版本的源碼,很簡(jiǎn)潔的使用了等其目的也很簡(jiǎn)單簡(jiǎn)化相關(guān)生態(tài)的繁瑣邏輯參考源碼地址 ??dva的思想還是很不錯(cuò)的,大大提升了開發(fā)效率,dva集成了Redux以及Redux的中間件Redux-saga,以及React-router等等。得益于Redux的狀態(tài)管理,以及Redux-saga中...

    txgcwm 評(píng)論0 收藏0
  • React生態(tài),dva源碼閱讀

    摘要:下面會(huì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁面后,每一個(gè)子頁面對(duì)應(yīng)一個(gè)文件??偨Y(jié)上面就是最早版本的源碼,很簡(jiǎn)潔的使用了等其目的也很簡(jiǎn)單簡(jiǎn)化相關(guān)生態(tài)的繁瑣邏輯參考源碼地址 ??dva的思想還是很不錯(cuò)的,大大提升了開發(fā)效率,dva集成了Redux以及Redux的中間件Redux-saga,以及React-router等等。得益于Redux的狀態(tài)管理,以及Redux-saga中...

    harryhappy 評(píng)論0 收藏0
  • Taro 優(yōu)秀學(xué)習(xí)資源匯總

    摘要:多端統(tǒng)一開發(fā)框架優(yōu)秀學(xué)習(xí)資源匯總官方資源項(xiàng)目倉庫官方文檔項(xiàng)目倉庫官方文檔微信小程序官方文檔百度智能小程序官方文檔支付寶小程序官方文檔字節(jié)跳動(dòng)小程序官方文檔文章教程不敢閱讀包源碼帶你揭秘背后的哲學(xué)從到構(gòu)建適配不同端微信小程序等的應(yīng)用小程序最 Awesome Taro 多端統(tǒng)一開發(fā)框架 Taro 優(yōu)秀學(xué)習(xí)資源匯總 showImg(https://segmentfault.com/img/r...

    toddmark 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<