初識react(五) 數據流終極解決方案 dva(零配置)

chaiguanpeng.github.io/

回顧

糾正下,零配置是由umi幫咱們實現的,不是dva幫咱們作的,可是dva-cli在下一個版本(即dva-cli 1.0)已經內置了umi,簡直開發者福音,有興趣朋友能夠體驗下最新版本。html

npm i dva-cli@next -g  //安裝下一代dva-cli,內置umi
dva new dvaTest
cd dvaTest
npm start
複製代碼

咱們這裏仍是從最基本的dva開始講起,瞭解流程。重點:dva並無發明新的概念,全都是之前提到的。只是進行了一層封裝,對redux、saga中的概念很清楚的話,dva就是白給你的,沒有難點,不會來找我。前端

簡介

  • 基於 redux、redux-saga 和 react-router 的輕量級前端框架。
  • dva是基於react+redux最佳實踐上實現的封裝方案,簡化了redux和redux-saga使用上的諸多繁瑣操做

數據流向

  • 數據的改變發生一般是經過:
    • 用戶交互行爲(用戶點擊按鈕等)
    • 瀏覽器行爲(如路由跳轉等)觸發的
  • 當此類行爲會改變數據的時候能夠經過 dispatch 發起一個 action,若是是同步行爲會直接經過 Reducers 改變 State ,若是是異步行爲(反作用)會先觸發 Effects 而後流向 Reducers 最終改變 State。

實現的demo效果

因爲dva比較簡單,沒有什麼新概念用例子講解會更明白。最後要實現一個異步獲取數據 num,而後點擊計數器 + num的效果react

  • 目錄結構

一、主入口文件

import React from 'react';
import dva from 'dva';
import Counter from './Counter';
//dva是一個函數,經過執行它能夠拿到一個app對象
let app = dva();
//一個模板就是一個狀態,而後把reducer和狀態 寫在一塊兒了,
//添加一個模塊
app.model({
   xxxx
});
//參數是一個函數,此應用自己就是要渲染函數的返回值
app.router(() => <Counter />);

//本質是啓動應用,就是經過app.router獲取組件,而且經過ReactDOM渲染到容器內容
app.start('#root');

複製代碼

以上是最基本的dva的主入口文件,簡單的3個API,app.model、app.router、app.start,就已經講react、redux-router、redux、redux-saga整合一塊兒,簡直開發者福音。咱們講解下怎麼用git

  • dva是一個函數,經過執行它能夠拿到一個app對象
  • app.model()添加一個模塊,下面重點講解
  • app.router()接受函數,而後渲染函數返回值
  • app.start('#root'),經過app.router獲取組件,而後經過ReactDom渲染到容器
1.一、app.model()用法
  • 接受一個對象,把state、reducers、effects所有寫在這,便於維護。
app.model({
    //命名空間。由於一個應用會有不少個模型,每一個模型要有一個名字
    namespace: 'counter',
    //此命名空間的默認狀態
    state: { current: 0, highest: 0 },
    //它是用來接收action,修改倉庫狀態的
    reducers: {
        save(state, action) {
            return { current:state.current+action.payload  };
        }
    }
});

複製代碼

看見這些名詞應該很熟悉吧github

  • namespace命名空間,咱們須要給模型一個名字
  • state=>狀態,就是redux中的狀態
  • reducers=>處理器,就是redux中的處理器

在強調遍,dva沒有發明新的概念,只是進行了一層封裝。讓狀態更利於維護express

二、編寫Counter.js組件

import React from 'react';
import { connect } from 'dva';
class Counter extends React.Component {
    render() {
        return (
            <div className="container">
                <div className="current">
                    當前記錄:{this.props.current}
                </div>
                <div className="addButton">
                    <button onClick={() => this.props.dispatch({ type: 'counter/save',payload:2 })}>+</button>
                </div>
            </div>
        )
    }
}
export default connect(
    state => {
        return state.counter;
    }
)(Counter);

複製代碼

不過多解釋,有2個地方須要注意:npm

  • 組件內部派發動做時,type:'counter/add',前面多了counter(命名空間)
  • connect時的狀態是總的狀態,須要制定下須要counter的狀態

目前爲止,dva流程已經跑通了,是否是很簡單,咱們測試下是否能點擊加2json

完美實現,說好的異步呢,接下來咱們用express編寫一個簡單接口redux

三、編寫服務端接口 server.js

咱們用express編寫簡單接口,不講解express用法。 express直通車跨域

let express = require('express');
let cors = require('cors'); //解決跨域的包
let app = express();
app.use(cors()); //使用中間件cors
app.get('/amount', function (req, res) {
    res.send({ num: 5 });
});
app.listen(3000);
複製代碼
  • 接下來啓動服務,看下效果

四、客戶端發請求獲取數據

因爲案例比較簡單,都寫在了src/index.js中

function getAmount() {
    return fetch('http://localhost:3000/amount', {
        headers: {
            "Accept": "application/json"
        }
    }).then(res => res.json());
}
複製代碼

五、在app.model中添加effects(反作用) (就是redux-saga中的effects)

effects: {
        //表示這是一個generator effect=redux-saga/effects
        *add(action, { call, put }) {
            let { num } = yield call(getAmount); 
            yield put({ type: 'save', payload: num });
        }
    },
複製代碼

先異步獲取數據,而後再派發動做修改狀態,接着刷新視圖

六、對應的組件新增一個異步記數的按鈕

<button onClick={() => this.props.dispatch({ type: 'counter/save',payload:2 })}>同步加2</button>
<button onClick={() => this.props.dispatch({ type: 'counter/add' })}>異步記數</button>
複製代碼
  • 增長了一個異步計數按鈕,會派發add動做類型。
  • add類型被effects(反作用)中的add監聽到,執行 getAmount()異步獲取數據
  • 拿到數據後派發save動做,被reducers處理
  • 頁面刷新

測試結果

完結

dva 簡化了redux和redux-saga使用上的諸多繁瑣操做,便於咱們開發,可維護性也更高,配合umi使用,號稱零配置,下篇文章會講解dva+umi使用

相關文章
相關標籤/搜索