Umi + Dva + Antd的React項目實踐


記錄一下最近項目所用到的技術React + Dva + Antd + umi ,以免忘記。之前沒有用過它們其中一個,也是慢慢摸索,了解數據整個流程。

先了解下概念

React 不多說,3大框架之一;

Dva 是由阿里架構師 sorrycc 帶領 team 完成的一套前端框架,在作者的 github 里是這么描述它的:“dva 是 react 和 redux 的最佳實踐”。現在已經有了自己的官網 https://dvajs.com;

Antd 是阿里的一套開箱即用的中台前端/設計解決方案,UI框架,官網 http://ant-design.gitee.io/index-cn;

umi 是 dva 作者 sorrycc 最近整的新玩意,2018.2.26 發布的 1.0 版本。sorrycc 認為之前 dva 固然好,但還要用戶自己引入 UI 工具 antd,打包工具 roadhog,路由 react-router,狀態管理器 dva,這些很麻煩,所以弄了這個,官網 https://umijs.org;

 

在dva中主要分3層,models,services,components,其中models是最重要概念,這里放的是各種數據,與數據交互的應該都是在這里。services是請求后台接口的方法。components是組件了。

services層:

export function doit (body) {
    return request({
        method: "post",
        url: `${wechatApi}/doit`,
        data: JSON.stringify(body),
    })
}

這里就是請求后台接口的方法,其中這里的request是封裝了axios的函數,所以它是返回的是一個promise對象,url就是要請求的地址,body就是請求參數了。

那個request如下

import axios from "axios"

export default async function request (options) {
    let response
    try {
        response = await axios(options)
        return response
    } catch (err) {
        return response
    }
}

models層:

export default {
    namespace: "test", //命名空間名字,必填  
    state: { num: 0 },//state就是用來放初始值的
    // 能改變界面的action應該放這里,這里按官方意思不應該做數據處理,只是用來return state 從而改變界面
    reducers:{
     addNum ( // addNum可以理解為一個方法名 
        // 這里state就是上面初始的state,這里理解是舊state
        state, { payload: { num }}// num 是傳過來的,名字隨便起,不是state中的num,這接收一個action       )         { //return新的state,這樣頁面就會更新 es6語法,就是把state全部展開,然后把num:num重新賦值,這樣后面賦值的num就會覆蓋前面的。也是es6語法,相同名字可以寫成一個,所以上面接收處寫了num
        return { ...state, num} 
      },   },
    // 與后台交互,處理數據邏輯的地方   effects:{
      * fetchNum({ payload2 }, { call, put,select }) {//fetchNum方法名,payload2是傳來的參數,是個對象,如果沒參數可以寫成{_,{call,put,select}}
        const { data } = yield call(myService.doit, {anum:payload2.numCount}) // myService是引入service層那個js的一個名字,anum是后台要求傳的參數,data就是后台返回來的數據
        //const m = yield select((state) => state.test.num) //select就是用來選擇上面state里的,這里沒用上
        yield put({
          type: "addNum",// 這就是reducer中addNum方法, put就是用來觸發上面reducer的方法,payload里就是傳過去的參數。 同時它也能觸發同等級effects中其他方法。
          payload: {
            num: data, // 把后台返回的數據賦值給了num,假如那個reducer中方法是由這里effects去觸發的,那個num名必須是這里名字num,如果reducer中方法不是這觸發,那名字可隨便起
          },
        })
   },
     * fetchUser(_,{call,put}) {
      // XXXXXXX代碼
    }
    },   subscriptions:{   
// 訂閱監聽,比如我們監聽路由,進入頁面就如何,可以在這寫;
     //這里的代碼,運行起來就會自動執行,在任意models寫都可以。而且方法名是任意的,這個setup是自己起的名字。
        setup ({ dispatch, history, query }) {
          return history.listen(async ({ pathname, search, query}) => {
            if (pathname==="/testdemo") {// 當進入testdemo這路由,就會觸發fetchUser方法
              dispatch({ type: "fetchUser" })
              }
          })
   } )

components層:

clickHandler = () => {
        dispatch({
                        type: "test/fetchNum",// 這里就會觸發models層里面effects中fetchNum方法(也可以直接觸發reducer中方法,看具體情況) ,test就是models里的命名空間名字
                        payload: {
                            numCount: ++1,
                        },
                    })
}

 

所以整體流程是:

點擊頁面按鈕,會觸發clickHandler,——>觸發models層effect的fetchNum——>觸發services層doit,獲取到后台返回數據——>觸發models層的addNum,把返回數據傳給addNum,再去更新models里的state,components應用了models層中的state的num的話,就會觸發頁面render方法重新渲染,界面就會更新。

render方法什么時候會觸發

當state或props變化時就會觸發render,我們一般在render里只獲取props和state,盡量不做邏輯處理(數據邏輯處理基本在render上面的函數或者models中處理)。當父組件給子組件傳遞props時,子組件那個props最好不要在render里面做邏輯計算賦值,不然傳遞過去,子

組件有可能拿不到最新的值。比如傳了個數組arr,arr在render里做了數據處理,賦值,render會運行多次(這里舉例3次)所以結果可能是[1,2,3] [1,2,3] [1,2],子組件拿到的值是[1,2,3]而不是最終的[1,2],所以當你出現

子組件無法獲取父組件傳遞過來最后正確的值,看看是不是值在render做了運算賦值,解決方法就是把數據邏輯放在models層處理,然后再返回,這樣就沒問題了。

 

頁面要應用models層的數據要用connect

import { Component } from "react"
import { connect } from "dva"


class TheDemo  extends Component {
    clickHandler = () =>{xxxx}
   render () {
    const {num} = this.props //獲取下面的num
        return (
        <div>
            <button onClick={this.clickHandler}><button>
            <p>{num}</p>
        </div>
)
    }
}

//字面意思就是,把models的state變成組件的props
function mapStateToProps (state) {
    const { num} = state.test // test就是models命名空間名字 
    return {
        num, // 在這return,上面才能獲取到
    }
}

export default connect(mapStateToProps)(TheDemo)    
            

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM