Dva框架從初識到上手


 

引言

最近工作需要用dva框架,同事幫我培訓了一下,有一點點認識,在此總結。

當然,以后對dva可能會了解更透徹,文章會不斷更新的。

 

初識

開始看架構代碼,沒有看文檔的時候,不知道里面的幾個關鍵字是什么意思:

  1. Effect
  2. Reducer
  3. Dispatch
  4. mapStateToProps
  5. NAMESPACE

一頭霧水,感覺好復雜。聽完同事講解以后,覺得redux代碼量好大。

雖然公司其他項目用的不是這個框架,但是最近項目需要,沒辦法,學唄!

 

關於dva

dva 是基於現有應用架構 (redux + react-router + redux-saga 等)的一層輕量封裝;

數據流向: 數據的改變發生通常是通過:

用戶交互行為(用戶點擊按鈕等)
瀏覽器行為(如路由跳轉等)觸發的
當此類行為會改變數據的時候可以通過 dispatch 發起一個 action ,如果是同步行為會直接通過Reducers 改變 State ,如果是異步行為(副作用)會先觸發 Effects 然后流向 Reducers 最終改變State 。 所以在 dva 中,數據流向非常清晰簡明,看最后思維導圖。

關於Redux-saga

Redus-saga 是一個 redux 的中間件,主要用來簡便而優雅的處理 redux 應用里的副作用(side effect相對於pure function這類概念而言的)。它之所以可以做到這一點主要是使用了ES6 里的一個語法: Generator 。使用 Generator 可以像寫同步的代碼一樣編寫異步代碼,這樣更加容易測試。(其實這里也不是特別懂,后面還要研究一下)

現在回頭看(雖然才過去兩天),感覺走了彎路。因為項目時間比較緊,同事跟我講完,我想都沒想,就按照他跟我說的邏輯,復制粘貼(在原來代碼基礎上),然后哪里報錯修哪里。

后來越弄越搞不清楚。所以,拿到新東西,開始一定是看文檔,看文檔,看文檔。

后來我看文檔,把不懂的再確認一遍,看一下之前別人是怎么寫的,然后從頭開始寫自己的任務:

1 添加路由(page)

2 添加布局以及組件

3 設計Model

4 connect關聯

 

上手

下面根據以上四個步驟,我們來看一個用例

這個就是同事跟我講解的時候寫的,很清晰明了

step1:routes

這里沒有寫組件,如果有組件這里可以抽出來。

關於多層級組件傳數據,我目前還不是完全明白,等后面搞明白了加上。

import React, { Component } from 'react'
import { connect } from 'dva'
import './index.less'
import { NAMESPACE } from '../../models/evaluateManage/constants';
import { Row , Col, Input, Button, Select } from 'antd'
const Option = Select.Option

const mapStateToProps = (state) => ({
    ...state[NAMESPACE],
    description: state[NAMESPACE].description,
    menuList: state[NAMESPACE].menuList,
})

const mapDispatchToProps = (dispatch) => ({
    dispatch,
    updateState(val, cb){
        dispatch({
            type:`${NAMESPACE}/updateState`,
            payload:{
                params: val,
                cb: cb
            }
        })
    },
    getMenu(val, cb){
        dispatch({
            type: `${NAMESPACE}/getMenu`,
            payload: {
                params: val,
                cb: cb
            }
        })
    }
})

@connect(mapStateToProps, mapDispatchToProps)
class EvaluateManage extends Component{

    constructor(props){
        super(props)
        this.state = {
            inputMsg: undefined
        }
    }
    syncMethod = () => {
        const { inputMsg } = this.state
        this.props.updateState({
            description: inputMsg
        }, (res) => {
            debugger
        })
    }
    asyncMethod = () => {
        this.props.getMenu({
            tenantId: "_1RNSq2S"
        })
    }
    asyncMethod = () => {
        this.props.getMenu({
            tenantId: "_1RNSq2S"
        })
    }
    asyncMethodCallback = () => {
        this.props.getMenu({
            tenantId: "_1RNSq2S"
        },(res = []) => {
            this.props.updateState({
                menuList: res,
                description: "通過回調機制"
            })
        })
    }

    inputMethod = (e) => {
        let value = e.target.value
        if(!value){
            value = "我是描述"
        }
        this.setState({
            inputMsg: value
        })
    }


    render(){
        const { inputMsg } = this.state
        const { menuList = [] } = this.props
        return <div styleName="rule-wrapper">
            <h1 styleName="ruleTitle">{this.props.description}</h1>
            <h1 styleName="ruleTitle">我是輸入內容:{inputMsg}</h1>
            <Row>
                <Col span={24}>
                    <Input onChange={this.inputMethod} value={inputMsg}/>
                </Col>
            </Row>
            <Row>
                <Col span={8}>
                    <Button size="large" onClick={this.syncMethod}>我是同步按扭</Button>
                </Col>
                <Col span={8}>
                    <Button size="large"  onClick={this.asyncMethod}>我是異步按扭</Button>
                </Col>
                <Col span={8}>
                    <Button size="large"  onClick={this.asyncMethodCallback}>我是異步按扭回調機制</Button>
                </Col>
            </Row>
            <ul>
                {
                    menuList.map((item) => {
                        const { name, code} = item
                        return <li>{name}   {code}</li>
                    })
                }
            </ul>
            
            
        </div>
    }
}

export default EvaluateManage

  inistate

const evaluateManage = {
    "description": "我是描述",
    "menuList": []
}

  model

import * as constants from './constants'
import {initState} from "../initState";
import {apiCallTemplate} from 'Apis/api'


export const getMenu = apiCallTemplate('getMenu', constants.NAMESPACE)


export default {
    namespace: constants.NAMESPACE,
    state: initState[constants.NAMESPACE],
    reducers: {
        updateState(state, { payload }){
            const { params, cb } = payload
            cb && cb()
            return {
                ...state,
                ...params
            }
        } 
    },
    effects: {
        *getMenu({ payload: {params = {},cb } }, { call, put}){
            const { data } = yield call(getMenu, params)
            const { menuList = [] } = data
            if(cb){
                cb(menuList)
            }else{
                yield put({
                    type: 'updateState',
                    payload: {
                        params: {
                            menuList,
                            description: "通過非回調機制"
                        }
                    }
                })
            }
            
        }
    },
    subscriptions: {},
}

 最終效果見下圖

  點擊同步按鈕

   點擊異步按鈕,這里調了getMenu接口

 

 異步和異步回調效果差不多的,后者多了回調

 

dva思維導圖

 dva框架思維導圖

 

 

寫在最后

model中的reducers跟effects是負責修改狀態state的方法,其中reducers是同步方法,effects是異步方法,reducers跟effects中的方法

組件中修改狀態需要通過在Action中調用dispatch方法來調用reduces或effects中的方法來實現,

因此需要在組件中定義Action方法,頁面根組件中的mapDispatchToProps里面負責定義Action,

所以在頁面根組件中需要在mapDispatchToProps中定義操作reducers或effects的方法(action)

 

dva將所有與數據操作相關的邏輯集中放在一個地方處理和維護,在數據跟業務狀態交互比較緊密的場景下,會使我們的代碼更加清晰可控。

對於一個大型管理系統,由於要進行大量的數據操作,在設計model時將不同類型的業務需求數據操作分開處理,便於維護。

項目的開發流程一般是從設計 model state 開始進行抽象數據,完成 component 后,將組件和model 建立關聯,通過 dispatch 一個 action ,在 reducer 中更新數據完成數據同步處理;

當需要從服務器獲取數據時,通過 Effects 數據異步處理,然后調用 Reducer 更新全局 state 。

以上一個單向的數據流動過程。

解決了 redux 中代碼分散和重寫問題。

總之,Dva:Build redux application easier and better。

這里代碼量確實比mobx的大,但這套框架也確實有可取之處。

阿里雲主要用的語言是React,架構: Redux,框架:dva

 

備注:

react高階組件學習

前端react迭代方向,盡量少用高階組件,后期不好維護。多將組件細分,組件越小越好,類似樂高積木一樣。

不過高階組件還是要會運用。

 


免責聲明!

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



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