国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React生態(tài),dva源碼閱讀

txgcwm / 1774人閱讀

摘要:下面會(huì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁(yè)面后,每一個(gè)子頁(yè)面對(duì)應(yīng)一個(gè)文件。總結(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中通過Task和Effect來(lái)處理異步的概念,dva在這些工具的基礎(chǔ)上高度封裝,只暴露出幾個(gè)簡(jiǎn)單的API就可以設(shè)計(jì)數(shù)據(jù)模型。

??最近看了一下Redux-saga的源碼,結(jié)合以及之前在項(xiàng)目中一直采用的是redux-dark模式來(lái)將reducers和sagas(generator函數(shù)處理異步)拆分到不同的子頁(yè)面,每一個(gè)頁(yè)面中同一個(gè)文件中包含了該頁(yè)面狀態(tài)的reducer和saga,這種簡(jiǎn)單的封裝已經(jīng)可以大大的提升項(xiàng)目的可讀性。

??最近看了dva源碼,熟悉了dva是在上層如何做封裝的。下面會(huì)從淺到深,淡淡在閱讀dva源碼過程中自己的理解。

redux-dark模式

dva 0.0.12版本的使用和源碼理解

本文的原文地址為: https://github.com/forthealll...
歡迎star

一、redux-dark模式

??在使用redux和redux-saga的時(shí)候,特別是如何存放reducer函數(shù)和saga的generator函數(shù),這兩個(gè)函數(shù)是直接跟如何處理數(shù)據(jù)掛鉤的。

??回顧一下,在redux中使用異步中間件redux-saga后,完整的數(shù)據(jù)和信息流向:

??在存在異步的邏輯下,在UI Component中發(fā)出一個(gè)plain object的action,然后經(jīng)過redux-saga這個(gè)中間件處理,redux-saga會(huì)將這個(gè)action傳入相應(yīng)channel,通過redux-saga的effect方法(比如call、put、apply等方法)生成一個(gè)描述對(duì)象,然后將這個(gè)描述對(duì)象轉(zhuǎn)化成具有副作用的函數(shù)并執(zhí)行。

??在redux-saga執(zhí)行具有副作用的函數(shù)時(shí),又可以dispatch一個(gè)action,這個(gè)action也是一個(gè)plain object,會(huì)直接傳入到redux的reducer函數(shù)中進(jìn)行處理,也就是說(shuō)在redux-saga的task中發(fā)出的action,就是同步的action。

簡(jiǎn)單的概括:從UI組件上發(fā)出的action經(jīng)過了2層的處理,分別是redux-saga中間件和redux的reducer函數(shù)。

??redux-dark模式很簡(jiǎn)單,就是將同一個(gè)子頁(yè)面下的redux-saga處理action的saga函數(shù),以及reducer處理該子頁(yè)面下的state的reducer函數(shù),放在同一個(gè)文件中。

舉例來(lái)說(shuō):

 import { connect } from "react-redux";
 class Hello extends React.Component{
     componentDidMount(){
       //發(fā)出一個(gè)action,獲取異步數(shù)據(jù)
       this.props.dispatch({
          type:"async_count"
       })
     }
     
 
 }
 export default connect({})(Hello);
 

從Hello組件中發(fā)出一個(gè)type = "async_count"的action,我們用redux-dark模式來(lái)將saga和reducer函數(shù)放在同一個(gè)文件中:

    import { takeEvery } from "redux-saga/effects";
    
    //saga
    function * asyncCount(){
      console.log("執(zhí)行了saga異步...")
      //發(fā)出一個(gè)原始的action
      yield put({
        type:"async"
      });
    }
    function * helloSaga(){
        //接受從UI組件發(fā)出的action
        takeEvery("async_count",asyncCount);
    }
    
    //reducer
    function helloReducer(state,action){
       if(action.type === "count");
       return { ...state,count + 1}
    }

上述就是一個(gè)將saga和reducer放在同一個(gè)文件里面的例子。redux-dark模式來(lái)組織代碼,可以顯得比較直觀,統(tǒng)一了數(shù)據(jù)的處理層。分拆子頁(yè)面后,每一個(gè)子頁(yè)面對(duì)應(yīng)一個(gè)文件。可讀性很高。

二、dva 0.0.12版本的使用和源碼理解

??上述的redux-dark模式,就是一種簡(jiǎn)單的處理,而dva的話是做了更近一步的封裝,dva不僅封裝了redux和redux-saga,還有react-router-redux、react-router等等。使得我們可以通過很簡(jiǎn)單的配置,就能使用redux、redux-saga、react-router等。

下面首先以dva的初始版本為例來(lái)理解一下dva的源碼。

(1)、dva 0.0.12的使用

來(lái)看官網(wǎng)給的使用dva 0.0.12的例子:

// 1. Initialize
const app = dva();

// 2. Model
app.model({
  namespace: "count",
  state: 0,
  effects: {
    ["count/add"]: function*() {
      console.log("count/add");
      yield call(delay, 1000);
      yield put({
        type: "count/minus",
      });
    },
  },
  reducers: {
    ["count/add"  ](count) { return count + 1 },
    ["count/minus"](count) { return count - 1 },
  },
  subscriptions: [
    function(dispatch) {
      //..處理監(jiān)聽等等函數(shù)
    }
  ],
  
});

// 3. View
const App = connect(({ count }) => ({
  count
}))(function(props) {
  return (
    

{ props.count }

); }); // 4. Router app.router(({ history }) => ); // 5. Start app.start(document.getElementById("root"));

只要三步就完成了一個(gè)例子,如何處理action呢,我們以一個(gè)圖來(lái)表示:

也就是做UI組件上發(fā)出的對(duì)象類型的action,先去根據(jù)類型匹配=model初始化時(shí)候,effects屬性中的action type。

如果在effects的屬性中有相應(yīng)的action type的處理函數(shù),那么先執(zhí)行effects中的相應(yīng)函數(shù),在執(zhí)行這個(gè)函數(shù)里面可以二次發(fā)出action,二次發(fā)出的action會(huì)直接傳入到reducer函數(shù)中。

如果effects的屬性中沒有相應(yīng)的action type的處理函數(shù),那么會(huì)直接從reducer中尋找有沒有相應(yīng)類型的處理函數(shù)。

在dva初始化過程中的effects屬性中的函數(shù),其實(shí)就是redux-saga中的saga函數(shù),在該函數(shù)中處理直接的異步邏輯,并且該函數(shù)可以二次發(fā)出同步的action。

此外dva還可以通過router方法初始化路由等。

(2)、dva 0.0.12的源碼閱讀

下面來(lái)直接讀讀dva 0.0.12的源碼,下面的代碼是經(jīng)過我精簡(jiǎn)后的dva的源碼:

//Provider全局注入store
import { Provider } from "react-redux";
//redux相關(guān)的api
import { createStore, applyMiddleware, compose, combineReducers } from "redux";
//redux-saga相關(guān)的api,takeEvery和takeLatest監(jiān)聽等等
import createSagaMiddleware, { takeEvery, takeLatest } from "redux-saga";
//react-router相關(guān)的api
import { hashHistory, Router } from "react-router";
//在react-router4.0之后已經(jīng)較少使用,將路由的狀態(tài)存儲(chǔ)在store中
import { routerMiddleware, syncHistoryWithStore, routerReducer as routing } from "react-router-redux";
//redux-actions的api,可以以函數(shù)式描述reducer等
import { handleActions } from "redux-actions";
//redux-saga非阻塞調(diào)用effect
import { fork } from "redux-saga/effects";

function dva() {
  let _routes = null;
  const _models = [];
  //new dva暴露了3個(gè)方法
  const app = {
    model,
    router,
    start,
  };
  return app;
  //添加models,一個(gè)model對(duì)象包含了effects,reducers,subscriptions監(jiān)聽器等等
  function model(model) {
    _models.push(model);
  }
  //添加路由
  function router(routes) {
    _routes = routes;
  }

  
  function start(container) {

    let sagas = {};
    //routing是react-router-redux的routerReducer別名,用于擴(kuò)展reducer,這樣以后擴(kuò)展后的reducer就可以處理路由變化。
    let reducers = {
      routing
    };
    _models.forEach(model => {
      //對(duì)于每一個(gè)model,提取其中的reducers和effects,其中reducers用于擴(kuò)展redux的reducers函數(shù),而effects用于擴(kuò)展redx-saga的saga處理函數(shù)。
      reducers[model.namespace] = handleActions(model.reducers || {}, model.state);
      //擴(kuò)展saga處理函數(shù),sagas是包含了所有的saga處理函數(shù)的對(duì)象
      sagas = { ...sagas, ...model.effects }; ---------------------------(1)
    });

    reducers = { ...reducers };
    
    //獲取決定使用React-router中的那一個(gè)api
    const _history = opts.history || hashHistory;
    //初始化redux-saga
    const sagaMiddleware = createSagaMiddleware();
    //為redux添加中間件,這里添加了處理路由的中間件,以及redux-saga中間件。
    const enhancer = compose(
      applyMiddleware.apply(null, [ routerMiddleware(_history), sagaMiddleware ]),
      window.devToolsExtension ? window.devToolsExtension() : f => f
    );
    const initialState = opts.initialState || {};
    //通過combineReducers來(lái)擴(kuò)展reducers,同時(shí)生成擴(kuò)展后的store實(shí)例
    const store = app.store = createStore(
      combineReducers(reducers), initialState, enhancer
    );

    // 執(zhí)行model中的監(jiān)聽函數(shù),監(jiān)聽函數(shù)中傳入store.dispatch
    _models.forEach(({ subscriptions }) => {
      if (subscriptions) {
        subscriptions.forEach(sub => {
         store.dispatch, onErrorWrapper);
        });
      }
    });
    
     // 根據(jù)rootSaga來(lái)啟動(dòng)saga,rootSaga就是redux-saga運(yùn)行的主task
    sagaMiddleware.run(rootSaga);
    
    
    //創(chuàng)建history實(shí)例子,可以監(jiān)聽store中的state的變化。
    let history;
    history = syncHistoryWithStore(_history, store); --------------------------------(2)
    

    // Render and hmr.
    if (container) {
      render();
      apply("onHmr")(render);
    } else {
      const Routes = _routes;
      return () => (
        
          
        
      );
    }

    function getWatcher(k, saga) {
      let _saga = saga;
      let _type = "takeEvery";
      if (Array.isArray(saga)) {
        [ _saga, opts ] = saga;
    
        _type = opts.type;
      }

      function* sagaWithErrorCatch(...arg) {
        try {
          yield _saga(...arg);
        } catch (e) {
          onError(e);
        }
      }

      if (_type === "watcher") {
        return sagaWithErrorCatch;
      } else if (_type === "takeEvery") {
        return function*() {
          yield takeEvery(k, sagaWithErrorCatch);
        };
      } else {
        return function*() {
          yield takeLatest(k, sagaWithErrorCatch);
        };
      }
    }

    function* rootSaga() {
      for (let k in sagas) {
        if (sagas.hasOwnProperty(k)) {
          const watcher = getWatcher(k, sagas[k]);
          yield fork(watcher);
        }                      -----------------------------(3)
      }
    }

    function render(routes) {
      const Routes = routes || _routes;
      ReactDOM.render((
        
          
        
      ), container);
    }
  }
}

export default dva;

代碼的閱讀在上面都以注視的方式給出,值得注意的主要有一下3點(diǎn):

在注釋(1)處, handleActions是通過redux-actions封裝后的一個(gè)API,用于簡(jiǎn)化reducer函數(shù)的書寫。下面是一個(gè)handleActions的例子:

const reducer = handleActions(
  {
    INCREMENT: (state, action) => ({
      counter: state.counter + action.payload
    }),
?
    DECREMENT: (state, action) => ({
      counter: state.counter - action.payload
    })
  },
  { counter: 0 }
);

INCREMENT和DECREMENT屬性的函數(shù)就可以分別處理,type = "INCREMENT"和type = "DECREMENT"的action。

在注釋 (2) 處,通過react-router-redux的api,syncHistoryWithStore可以擴(kuò)展history,使得history可以監(jiān)聽到store的變化。

在注釋(3)處是一個(gè)rootSaga, 是redux-saga運(yùn)行的時(shí)候的主Task,在這個(gè)Task中我們這樣定義:

function* rootSaga() {
  for (let k in sagas) {
    if (sagas.hasOwnProperty(k)) {
      const watcher = getWatcher(k, sagas[k]);
      yield fork(watcher);
    }                     
  }
}

從全局的包含所有saga函數(shù)的sagas對(duì)象中,獲取相應(yīng)的屬性,并fork相應(yīng)的監(jiān)聽,這里的監(jiān)聽常用的有takeEvery和takeLatest等兩個(gè)redux-saga的API等。

總結(jié):上面就是dva最早版本的源碼,很簡(jiǎn)潔的使用了redux、redux-saga、react-router、redux-actions、react-router-redux等.其目的也很簡(jiǎn)單:

簡(jiǎn)化redux相關(guān)生態(tài)的繁瑣邏輯

參考源碼地址:https://github.com/dvajs/dva/...

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/101394.html

相關(guān)文章

  • React生態(tài)dva源碼閱讀

    摘要:下面會(huì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁(yè)面后,每一個(gè)子頁(yè)面對(duì)應(yīng)一個(gè)文件。總結(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ì)從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁(yè)面后,每一個(gè)子頁(yè)面對(duì)應(yīng)一個(gè)文件。總結(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
  • 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的移動(dòng)端和PC端生態(tài)圈的使用匯總

    摘要:調(diào)用通過注冊(cè)表調(diào)用到實(shí)例,透過的,調(diào)用到中的,最后通過,調(diào)用,根據(jù)參數(shù)相應(yīng)模塊執(zhí)行。京東的,多端解決方案是一套遵循語(yǔ)法規(guī)范的多端開發(fā)解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對(duì)于一項(xiàng)技術(shù),我們不能停留在五分鐘狀態(tài),特別喜歡一句話,用什么方式繪制UI界面一點(diǎn)不重要,重要的是底層的思維,解決問題和優(yōu)化...

    kun_jian 評(píng)論0 收藏0
  • React的移動(dòng)端和PC端生態(tài)圈的使用匯總

    摘要:調(diào)用通過注冊(cè)表調(diào)用到實(shí)例,透過的,調(diào)用到中的,最后通過,調(diào)用,根據(jù)參數(shù)相應(yīng)模塊執(zhí)行。京東的,多端解決方案是一套遵循語(yǔ)法規(guī)范的多端開發(fā)解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對(duì)于一項(xiàng)技術(shù),我們不能停留在五分鐘狀態(tài),特別喜歡一句話,用什么方式繪制UI界面一點(diǎn)不重要,重要的是底層的思維,解決問題和優(yōu)化...

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

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

0條評(píng)論

txgcwm

|高級(jí)講師

TA的文章

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