Dva.js 快速上手指南

来源:https://www.cnblogs.com/fx67ll/archive/2022/10/20/dva-quick-start.html
-Advertisement-
Play Games

先說些廢話 最近在開發React技術棧的項目產品,對於數據狀態的管理使用了Dva.js,作為一個資深的ow玩家,我看到這個名字第一反應就是————這不是ow里的一個女英雄嗎?仔細閱讀了官方文檔之後,發現開發者還真是因為這個角色獲得靈感,來命名這個數據狀態管理插件,果然開發大佬都是工作和休閑兩不誤~ ...


先說些廢話

最近在開發React技術棧的項目產品,對於數據狀態的管理使用了Dva.js,作為一個資深的ow玩家,我看到這個名字第一反應就是————這不是ow里的一個女英雄嗎?仔細閱讀了官方文檔之後,發現開發者還真是因為這個角色獲得靈感,來命名這個數據狀態管理插件,果然開發大佬都是工作和休閑兩不誤~

學過React的同學都知道它的技術棧非常多且雜,所以每當你使用React的時候都需要引入很多的模塊,那麼Dva就是把這些用到的模塊集成在一起,比如一些需要引入的依賴react-saga/react-loger、必寫的ReactDOM.renderprovider、connect包裹等都省去不寫,形成一定的架構規範,大大提高我們的開發效率

今天,就來寫一份文檔,幫助後續使用Dva的開發者更好得在實際項目中(PS:需要是以UMI為基礎框架,純Dva來構建項目可以直接看文章結尾的參考文檔列表)上手使用

什麼是Dva

Dva首先是一個基於reduxredux-saga的數據流方案,然後為了簡化開發體驗,Dva還額外內置了react-routerfetch,所以也可以理解為一個輕量級的應用框架。

在我目前的項目中,更多是使用數據狀態管理的功能,他在我司的fish框架中做了內嵌,在主流的React開發框架UMI中也做了內嵌適配,使用起來非常方便快速。

Dva設計的目的就是簡化元素,降低難度,讓你不用管他怎麼實現的,我們按照預設的這個規則去寫就可以

數據流向

數據的改變發生通常是通過用戶交互行為或者瀏覽器行為(如路由跳轉等)觸發的,當此類行為會改變數據的時候可以通過dispatch發起一個action,如果是同步行為會直接通過reducers改變states,如果是非同步行為(副作用)會先觸發effects然後流向reducers最終改變states

Dva數據流向

分層開發

無論是Vue還是React開發,實際的大型應用一定有嚴格的分層開發規範,確保後續開發的可維護性,主要的分層結構有以下幾點:

  • Page 負責與用戶直接打交道:渲染頁面,接受用戶的操作輸入,側重於展示型交互性邏輯,這裡需要瞭解無狀態組件
  • Model 負責處理業務邏輯,為 Page 做數據、狀態的讀寫、變換、暫存等,Dvamodel就是做了這一層的操作
  • Service 負責與 HTTP 介面對接,進行純粹的數據讀寫

基礎概念

  1. namespace
    • model的命名空間,同時也是他在全局state上的屬性
    • 只能用字元串,不支持通過.的方式創建多層命名空間,相當於這個modelkey
    • 在組件裡面,通過connect這個key將想要引入的model加入
    import { connect } from 'dva';
    export default connect(({ namespaceValue }) => ({ ...namespaceValue }))(DvaCompoent);
    
  2. state
    • 表示model的狀態數據
    • 操作的時候每次都要當作不可變數據immutable data來對待,保證每次都是全新對象,沒有引用關係
  3. reducer
    • 必須是純函數,有固定輸入輸出,主要目的是修改自身state
    • 接受兩個參數:之前已經累積運算的結果和當前要被累積的值,返回的是一個新的累積結果,該函數把一個集合歸併成一個單值
    • 需要註意的是同樣的輸入必然得到同樣的輸出,它們不應該產生任何副作用effect。並且,每一次的計算都應該使用immutable data
  4. effect
    • 主要用於非同步請求,介面調用之類的
    • effect被稱為副作用,在我們的應用中,最常見的就是非同步操作
    • 它來自於函數編程的概念,之所以叫副作用是因為它使得我們的函數變得不純,同樣的輸入不一定獲得同樣的輸出
  5. subscription
    • subscription語義是訂閱,用於訂閱一個數據源,然後根據條件dispatch需要的action
    • 數據源可以是當前的時間、伺服器的websocket連接、keyboard輸入、geolocation變化、history路由變化等等
    • 內部定義的函數都會被被執行,執行之後作為監聽來處理事務
  6. dispatch
    • dispatch是一個用於觸發action的函數,action是改變state的唯一途徑,但是它只描述了一個行為,而dipatch可以看作是觸發這個行為的方式,reducer則是描述如何改變數據的
    • Dva中,connect model的組件通過props可以訪問到dispatch,可以調用model中的reducer或者effects
    import { connect } from 'dva';
    const testCom = props => {
      const { dispatch } = props;
      const changeValue = (id, val) => {
    	  // 調用reducer,一般是同步修改state中的值
          dispatch({
            type: 'dva/save',
            payload: {
              param: val
            },
          });
    	  // 調用effect,一般是發送後臺請求
    	  dispatch({
    	    type: 'dva/queryValue',
    	    payload: {
    	      id: id
    	    },
    	  });
        };
      return(
        <div>'hello world'</div>
      )
    }
    export default connect(({ dva }) => ({ ...dva }))(testCom);
    

Model中的Effects函數解析

需要註意的是:Effects裡面的函數都是Generator函數

  1. yield
    • 固定關鍵詞,Generator函數自帶的關鍵詞,和*搭配使用,有點像asyncawait,使用*則表明它是Generator函數
    • 然後每使用一個yield就是告訴程式這裡是非同步,需要等待這個後面的代碼執行完成,同步代碼可不使用該關鍵詞
  2. payload
    • 頁面上通過dispatch傳過來的payload同名參數
  3. select
    • DvaEffects函數的固定傳參
    • 用於拿到modelstate的數據,需要註意的是,state後面跟命名空間namespace的值
    const data = yield select((state) => state.namespaceName.valueName);
    
  4. call
    • DvaEffects函數的固定傳參
    • 第一個參數是一個非同步函數,payload是參數,可以通過call來執行一個完整的非同步請求,又因為yield的存在,就實現了非同步轉同步的方案
    const { data } = yield call(queryInterface, payload);
    
  5. put
    • DvaEffects函數的固定傳參
    • 可以使用同model中的Reducers或者Effects,通過Reducers來實現數據到頁面的更新,也可以通過put實現Effects的嵌套使用
    yield put({
    	type: 'save',
    	payload: {
    	  ...payload
    	},
    });
    

開發目錄

由於公司的fish框架以及常見的umi框架都對Dva做了深度繼承,會預設將src/models下的model定義自動掛載,只需要在model文件夾中新建文件即可新增一個model用來管理組件狀態,對於某個page文件夾下麵的model也會預設掛載

├─assets `靜態資源`
├─components `公共組件`
├─config `路由和環境配置`
├─constants `全局靜態常量`
├─locale `國際化`
│  ├─en_US `英文配置`
│  └─zh_CN `中文配置`
├─models `全局數據狀態` *Dva涉及的目錄*
├─pages `頁面目錄,用我參與開發的其中一個目錄來作為示例` *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組件數據狀態管理` *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函數是一種柯里化寫法

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);

柯里化

柯里化是把接受多個參數的函數轉換成接受一個單一參數的函數(PS:Scala語言中也有類似的設計)

// 柯里化
var foo = function(x) {
	return function(y) {
		return x + y
	}
}
foo(3)(4)


// 普通方法
var add = function(x, y) {
	return x + y;
}
add(3, 4) 

無狀態組件

創建無狀態組件是為了創建純展示組件,這種組件只負責根據傳入的props來展示,不涉及到要改變state狀態的操作,
在實際項目中頁面組件被寫成無狀態的組件,通過簡單組合可以構建成頁面或複雜組件,通過多個簡單組件來合併成一個複雜的大應用

const NoStateComponent = props => {
  const { helloWorld = 'hello world'} = props;
  return(
    <div>{ helloWorld }</div>
  )
}
export default NoStateComponent;

無狀態組件的優點

  1. 由於是無狀態組件,所以無狀態組件就不會在有組件實例化的過程,無實例化過程也就不需要分配多餘的記憶體,從而性能得到一定的提升
  2. 代碼整潔、可讀性高,對於大型項目的開發維護非常有好處

參考文檔一 ———— Dva官方文檔
參考文檔二 ———— UMI官方文檔
參考文檔三 ———— REACT基礎筆記 MODEL分層
參考文檔四 ———— 前端數據流方案Dva
參考文檔五 ———— 淺析dva (史上最全的dva用法及分析)
參考文檔六 ———— 【dva】model中effects函數的解析
參考文檔七 ———— Generator 函數的詳解
參考文檔八 ———— React connect()() 雙括弧 --柯里化寫法
參考文檔九 ———— 高級函數技巧-函數柯里化

我是 fx67ll.com,如果您發現本文有什麼錯誤,歡迎在評論區討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是資料庫事務? 事務,就是一系列操作的整體,其結果就是這一系列操作要麼全部成功,要麼全部失敗。 譬如說,一個經典的例子--轉賬。 A要轉帳給B 100塊錢,要經歷以下步驟: 1、扣除A賬戶100塊錢。 2、增加B賬戶100塊錢。 以上例子里的兩個步驟,要麼全部成功,要麼全部失敗,不然,就亂套了。 ...
  • 某能源企業成立於2008年,是成品油銷售領域的龍頭企業(以下簡稱“A企業”),由中外合資設立。A企業立足於陝西省及周邊地區,重點開展加油站運營管理及相關業務。目前在陝西、山西、河南、內蒙古自治區運營油站超過600座,會員超過600萬,每天為超過22萬名顧客提供高品質的燃油服務。 ...
  • where 子句,通常用於在找尋數據的時候做一個條件篩選,得到滿足條件的記錄行數; 註意:新增(insert)不能做篩選; where 子句中常見的運算符有如下幾種: 1. 比較運算符:> >= < <= != = 2. 算術運算符:+ - * / 3. 邏輯運算符:&(邏輯與——語法:and);| ...
  • 定義:select語句中嵌套select語句,被嵌套的select語句是子查詢。 子查詢可以出現在: select ....(select).. from ....(select).. where ....(select).. 1.where後面嵌套子查詢 select * from emp whe ...
  • 2008年,《鬥羅大陸》正式發行,成為了風靡一時的長篇玄幻小說。小說講述了穿越到鬥羅大陸的唐三如何一步步修煉武魂,由人修煉為神,最終鏟除了邪惡力量,成為了鬥羅大陸最強者的故事。此後數十年,《鬥羅大陸》成為了一代人心目中珍貴的記憶。每個鬥羅迷藉由小說想象了一個屬於自己的鬥羅大陸,可以在裡面組隊修真、盡 ...
  • 全民買量時代,新服和新區持續增開,對玩家長線留存及付費提升顯得尤為重要。在分析游戲活動效果和玩家營運數據時,相信大家都曾有過這樣的疑問: 不同區服玩家的表現如何對比分析? 怎樣合理評估新開區服對玩家迴流的持續吸引力? 高性價比的新服激勵是否有效提升了ARPU? … HMS Core分析服務全新上線6 ...
  • 下麵是我自己寫的一個功能,先分析下思路: 效果使用@keyframes幀動畫,屬性使用opacity和transform motto是有限的,而漂浮是無限的,需要迴圈有限的motto不斷創建新的漂浮 用一個pool來容納漂浮,在無操作的時候清空pool 本來是隨便寫寫的,但是改著改著...怎麼看起來 ...
  • 每日演算法 今日是: 1、將字元串轉換為駝峰格式 2、判斷字元串中是否有連續重覆的字元 將字元串轉換成駝峰格式 // css 中經常有類似 background-image 這種通過 - 連接的字元,通過 javascript 設置樣式的時候需要將這種樣式轉換成 backgroundImage 駝峰格 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...