通過前面四篇的鋪墊,終於輪到咱們的主角dva了,就是下面這個美女:css
先擦一擦哈喇子,咱們來介紹一下,dva出自於暴雪出品的一款遊戲《守望先鋒》,援引官方的角色介紹:前端
D.Va擁有一部強大的機甲,它具備兩臺全自動的近距離聚變機炮、可使機甲飛躍敵人或障礙物的推動器、 還有能夠抵禦來自正面的遠程攻擊的防護矩陣。react
而後呢,螞蟻金服的一位架構師sorrycc很迷這位美女,正巧剛開發了一款前端框架沒有名字,做爲一個向女神獻禮的項目,dva框架就此誕生。git
實際上,dva只是基於現有開源框架的一層輕量封裝,並無引入任何新概念:github
再來看一下框架圖,是否是都是熟悉的配方,熟悉的味道?web
固然,也不是徹底沒有新東西,其中有一個Subscription好像以前沒有見過,這是一種數據源訂閱機制,數據源能夠是鍵盤輸入事件、路由變化、服務器的 websocket 鏈接等等。你能夠在數據發生變化時收到通知,並派發必要的action。redux
實際上,dva是一個整合者,它的目標是解決「Code is everywhere」問題。當咱們同時使用上面這些框架時,通常會呈現下面這種類型的文件結構:segmentfault
+ src
+ sagas
- user.js
+ reducers
- user.js
+ actions
- user.js
複製代碼
而後,當咱們須要實現一個功能時,就須要在這幾個文件之間來回切換。。。api
另外一方面,dva還試圖隱藏一些常常重複書寫的routine代碼,讓開發者可以更加專一於業務邏輯。好比咱們寫一個應用的入口文件,須要作下面這麼多事情:bash
實際上,可能95%以上的項目中這些代碼都是如出一轍的,咱們不須要每次都花費時間來從新寫一遍這些代碼。
下面開始正式介紹dva 1.0相關的內容,dva 2.0作了一些優化升級,後面專門有一節介紹具體變化。
其實基本都是前面幾篇文章裏介紹過的概念:
最終寫出來的model.js會相似下面這個樣子,能夠發現全部相關代碼都放到一塊兒了,不須要在多個文件之間來回切換了(這裏的namespace就是之前Redux中的reducer的名字):
export default {
namespace: 'transactions',
state: {
txs: []
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
if (location.pathname === '/transactions/list') {
dispatch({type: 'fetch'});
}
});
},
},
effects: {
*fetch({ payload }, {call, select, put}) {
const { result } = yield call(apis.fetchTxs)
yield put({type:'addTx', payload: result})
},
},
reducers: {
addTx(state, { payload }) {
return { ...state, txs: payload };
},
},
}
複製代碼
dva只有7個API,因此上手基本上沒有什麼難度:
下面這個連接展現了5步建立單頁應用的例子:github.com/sorrycc/blo…
這個主要是從代碼結構上來劃分的,通常分爲下面4類模塊:
另外,因爲dva 1.0使用的是react-router v3,因此最外層還有一個router.js用於配置靜態路由。因此通常的目錄結構以下所示:
+ src/
+ services/
- users.js
+ models/
- users.js
+ components/
+ users/
- users.js
- users.css
+ routes/
- users.js
- router.js
複製代碼
dva 2.0中採用了react-router v4,就不須要router.js了。另外,如今官方推薦搭配使用umi(烏米,sorrycc最新的開源項目),能夠自動幫你註冊model、根據目錄結構生成路由配置,目錄結構會變成下面這個樣子:
+ src/
+ models/
- global.js
+ pages/
+ users/
+ index.js
+ services
- users.js
+ models/
- users.js
+ components/
+ users/
- users.js
- users.css
複製代碼
能夠發現,把route以及相關聯的model都放到pages目錄中了,能夠達到減小耦合,一刪全刪的功能。
前面提到過一個API能夠註冊「插件」,所謂插件就是一些生命週期「鉤子(hooks)」,能夠在事件發生時作一些額外處理。包括下面這些類型的鉤子:
一個比較典型的例子是頁面加載數據時轉圈圈,加載完畢後隱藏,這是一個不少地方都須要用到的場景。官方提供了一個dva-loading插件,能夠自動在異步請求數據時把loading設置爲true,得到數據後把loading設置爲false。這樣你就能夠在組件中綁定loading實現轉圈圈的自動控制了:
// index.js
import createLoading from 'dva-loading';
app.use(createLoading());
// components
function mapStateToProps(state) {
const { list, total, page } = state.users;
return {
loading: state.loading.models.users,
list,
total,
page,
};
}
複製代碼
雖然dva只是一層輕量級封裝,可是作了一些特殊的命名約定,剛開始寫代碼的時候會有點迷糊,搞不清楚跟以前直接使用redux+saga的時候的對應關係,這裏也幫你們梳理一下。
直接使用redux+saga的流程以下所示:
使用dva時的流程以下所示:(觸發effect爲例)
目前dva已經進化到2.0版本,除了採用了react-router v4之外,還有一些細節上的變更:
dispatch一個effect 類型的action時返回一個Promise,方便視圖層回調
新增 dynamic 接口,配合 react-router@4 處理組件的按需加載
take 自動補全 namespace 前綴
effect 先後會額外觸發 /@@start
和 /@@end
的 action,可利用此約定實現 put 的同步執行
同名 reducer 和 effect 不會 fallthrough(即二者都執行),而是僅執行 effect
具體細節能夠參見:github.com/sorrycc/blo…
今天就說到這裏,老規矩,上一張思惟導圖結束本篇文章:
參考: