Dva.js 快速上手指南
先說些廢話
最近在開發(fā)React技術(shù)棧的項目產(chǎn)品,對于數(shù)據(jù)狀態(tài)的管理使用了Dva.js,作為一個資深的ow玩家,我看到這個名字第一反應(yīng)就是————這不是ow里的一個女英雄嗎?仔細(xì)閱讀了官方文檔之后,發(fā)現(xiàn)開發(fā)者還真是因為這個角色獲得靈感,來命名這個數(shù)據(jù)狀態(tài)管理插件,果然開發(fā)大佬都是工作和休閑兩不誤~
學(xué)過React的同學(xué)都知道它的技術(shù)棧非常多且雜,所以每當(dāng)你使用React的時候都需要引入很多的模塊,那么Dva就是把這些用到的模塊集成在一起,比如一些需要引入的依賴react-saga/react-loger、必寫的ReactDOM.render、provider、connect包裹等都省去不寫,形成一定的架構(gòu)規(guī)范,大大提高我們的開發(fā)效率
今天,就來寫一份文檔,幫助后續(xù)使用Dva的開發(fā)者更好得在實際項目中*(PS:需要是以UMI為基礎(chǔ)框架,純Dva來構(gòu)建項目可以直接看文章結(jié)尾的參考文檔列表)*上手使用
什么是Dva
Dva首先是一個基于redux和redux-saga的數(shù)據(jù)流方案,然后為了簡化開發(fā)體驗,Dva還額外內(nèi)置了react-router和fetch,所以也可以理解為一個輕量級的應(yīng)用框架。
在我目前的項目中,更多是使用數(shù)據(jù)狀態(tài)管理的功能,他在我司的fish框架中做了內(nèi)嵌,在主流的React開發(fā)框架UMI中也做了內(nèi)嵌適配,使用起來非常方便快速。
Dva設(shè)計的目的就是簡化元素,降低難度,讓你不用管他怎么實現(xiàn)的,我們按照默認(rèn)的這個規(guī)則去寫就可以
數(shù)據(jù)流向
數(shù)據(jù)的改變發(fā)生通常是通過用戶交互行為或者瀏覽器行為(如路由跳轉(zhuǎn)等)觸發(fā)的,當(dāng)此類行為會改變數(shù)據(jù)的時候可以通過dispatch發(fā)起一個action,如果是同步行為會直接通過reducers改變states,如果是異步行為(副作用)會先觸發(fā)effects然后流向reducers最終改變states
分層開發(fā)
無論是Vue還是React開發(fā),實際的大型應(yīng)用一定有嚴(yán)格的分層開發(fā)規(guī)范,確保后續(xù)開發(fā)的可維護(hù)性,主要的分層結(jié)構(gòu)有以下幾點:
- Page 負(fù)責(zé)與用戶直接打交道:渲染頁面,接受用戶的操作輸入,側(cè)重于展示型交互性邏輯,這里需要了解無狀態(tài)組件
- Model 負(fù)責(zé)處理業(yè)務(wù)邏輯,為 Page 做數(shù)據(jù)、狀態(tài)的讀寫、變換、暫存等,Dva中model就是做了這一層的操作
- Service 負(fù)責(zé)與 HTTP 接口對接,進(jìn)行純粹的數(shù)據(jù)讀寫
基礎(chǔ)概念
- model的命名空間,同時也是他在全局state上的屬性
- 只能用字符串,不支持通過.的方式創(chuàng)建多層命名空間,相當(dāng)于這個model的key
- 在組件里面,通過connect這個key將想要引入的model加入
- 表示model的狀態(tài)數(shù)據(jù)
- 操作的時候每次都要當(dāng)作不可變數(shù)據(jù)immutable data來對待,保證每次都是全新對象,沒有引用關(guān)系
- 必須是純函數(shù),有固定輸入輸出,主要目的是修改自身state
- 接受兩個參數(shù):之前已經(jīng)累積運算的結(jié)果和當(dāng)前要被累積的值,返回的是一個新的累積結(jié)果,該函數(shù)把一個集合歸并成一個單值
- 需要注意的是同樣的輸入必然得到同樣的輸出,它們不應(yīng)該產(chǎn)生任何副作用effect。并且,每一次的計算都應(yīng)該使用immutable data
- 主要用于異步請求,接口調(diào)用之類的
- effect被稱為副作用,在我們的應(yīng)用中,最常見的就是異步操作
- 它來自于函數(shù)編程的概念,之所以叫副作用是因為它使得我們的函數(shù)變得不純,同樣的輸入不一定獲得同樣的輸出
- subscription語義是訂閱,用于訂閱一個數(shù)據(jù)源,然后根據(jù)條件dispatch需要的action
- 數(shù)據(jù)源可以是當(dāng)前的時間、服務(wù)器的websocket連接、keyboard輸入、geolocation變化、history路由變化等等
- 內(nèi)部定義的函數(shù)都會被被執(zhí)行,執(zhí)行之后作為監(jiān)聽來處理事務(wù)
- dispatch是一個用于觸發(fā)action的函數(shù),action是改變state的唯一途徑,但是它只描述了一個行為,而dipatch可以看作是觸發(fā)這個行為的方式,reducer則是描述如何改變數(shù)據(jù)的
- 在Dva中,connect model的組件通過props可以訪問到dispatch,可以調(diào)用model中的reducer或者effects
Model中的Effects函數(shù)解析
需要注意的是:Effects里面的函數(shù)都是Generator函數(shù)
- 固定關(guān)鍵詞,Generator函數(shù)自帶的關(guān)鍵詞,和*搭配使用,有點像async和await,使用*則表明它是Generator函數(shù)
- 然后每使用一個yield就是告訴程序這里是異步,需要等待這個后面的代碼執(zhí)行完成,同步代碼可不使用該關(guān)鍵詞
- 頁面上通過dispatch傳過來的payload同名參數(shù)
- Dva中Effects函數(shù)的固定傳參
- 用于拿到model中state的數(shù)據(jù),需要注意的是,state后面跟命名空間namespace的值
- Dva中Effects函數(shù)的固定傳參
- 第一個參數(shù)是一個異步函數(shù),payload是參數(shù),可以通過call來執(zhí)行一個完整的異步請求,又因為yield的存在,就實現(xiàn)了異步轉(zhuǎn)同步的方案
- Dva中Effects函數(shù)的固定傳參
- 可以使用同model中的Reducers或者Effects,通過Reducers來實現(xiàn)數(shù)據(jù)到頁面的更新,也可以通過put實現(xiàn)Effects的嵌套使用
開發(fā)目錄
由于公司的fish框架以及常見的umi框架都對Dva做了深度繼承,會默認(rèn)將src/models下的model定義自動掛載,只需要在model文件夾中新建文件即可新增一個model用來管理組件狀態(tài),對于某個page文件夾下面的model也會默認(rèn)掛載
├─assets `靜態(tài)資源` ├─components `公共組件` ├─config `路由和環(huán)境配置` ├─constants `全局靜態(tài)常量` ├─locale `國際化` │ ├─en_US `英文配置` │ └─zh_CN `中文配置` ├─models `全局?jǐn)?shù)據(jù)狀態(tài)` *Dva涉及的目錄* ├─pages `頁面目錄,用我參與開發(fā)的其中一個目錄來作為示例` *Dva涉及的目錄* │ ├─NodeConfig `NodeConfig示例目錄` │ │ ├─components │ │ │ ├─Select `Select組件頁面文件` *Dva涉及的目錄* │ │ │ │ └─components │ │ │ │ ├─AudienceInfo │ │ │ │ │ ├─index.js │ │ │ │ │ └─index.less │ │ │ │ ├─BlackList │ │ │ │ │ ├─index.js │ │ │ │ │ └─index.less │ │ │ │ ├─ControlGroup │ │ │ │ │ ├─index.js │ │ │ │ │ └─index.less │ │ │ │ └─GroupSelect │ │ │ │ │ ├─index.js │ │ │ │ │ └─index.less │ │ │ │ ├─index.js │ │ │ │ └─index.less │ │ ├─models │ │ │ ├─select.js `Select組件數(shù)據(jù)狀態(tài)管理` *Dva涉及的目錄* │ │ └─services ├─services `全局接口配置` ├─themes `全局樣式主題` └─utils `js通用工具`PS: 該樹形圖通過 `windows shell` 自帶的 `tree` 命令生成如何使用Dva
首先定義一個簡易的model示例
export default {namespace: 'dva',state: {id: '',value: {},},effects: {// 所有effect前必須要加 **queryValue({ payload }, { select, call, put }) {const params = {id: payload.id ? payload.id : yield select(state => state.select.id)}const { data } = yield call(queryInterface, params); // queryInterface是定義好的后臺請求接口,一般用axios或fetch來完成yield put({ type: 'save', payload: data });},},reducers: {save(state, { payload }) {return {...state,...payload,};},},subscriptions: {keyboardWatcher({ dispatch }) {key('?+up, ctrl+up', () => { dispatch( {type:'save'}) });},}, };然后把model和組件綁定在一起
React的Connect函數(shù)是一種柯里化寫法
import { connect } from 'dva';const testCom = props => {const { helloWorld = 'hello world'} = props;return(<div>{ helloWorld }</div>) }// 綁定之后就可以在testCom組件中使用命名為dva的model了 export default connect(({ dva }) => ({ ...dva }))(testCom);
柯里化
柯里化是把接受多個參數(shù)的函數(shù)轉(zhuǎn)換成接受一個單一參數(shù)的函數(shù)(PS:Scala語言中也有類似的設(shè)計)
// 柯里化 var foo = function(x) {return function(y) {return x + y} } foo(3)(4)// 普通方法 var add = function(x, y) {return x + y; } add(3, 4)
無狀態(tài)組件
創(chuàng)建無狀態(tài)組件是為了創(chuàng)建純展示組件,這種組件只負(fù)責(zé)根據(jù)傳入的props來展示,不涉及到要改變state狀態(tài)的操作,
在實際項目中頁面組件被寫成無狀態(tài)的組件,通過簡單組合可以構(gòu)建成頁面或復(fù)雜組件,通過多個簡單組件來合并成一個復(fù)雜的大應(yīng)用
無狀態(tài)組件的優(yōu)點
參考文檔一 ———— Dva官方文檔
參考文檔二 ———— UMI官方文檔
參考文檔三 ———— REACT基礎(chǔ)筆記 MODEL分層
參考文檔四 ———— 前端數(shù)據(jù)流方案Dva
參考文檔五 ———— 淺析dva (史上最全的dva用法及分析)
參考文檔六 ———— 【dva】model中effects函數(shù)的解析
參考文檔七 ———— Generator 函數(shù)的詳解
參考文檔八 ———— React connect()() 雙括號 --柯里化寫法
參考文檔九 ———— 高級函數(shù)技巧-函數(shù)柯里化
我是 fx67ll.com,如果您發(fā)現(xiàn)本文有什么錯誤,歡迎在評論區(qū)討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~ 😃
轉(zhuǎn)發(fā)請注明參考文章地址,非常感謝!!!
總結(jié)
以上是生活随笔為你收集整理的Dva.js 快速上手指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中wps默认安装目录,在Lin
- 下一篇: html 弹窗实现拖拽,原生js实现自由