Ant Design Pro 腳手架+umiJS 實踐總結

心晴安夏發表於2019-08-12

一、簡介

1、Ant Design Pro

Ant Design Pro是一款搭建中後臺管理控制檯的腳手架 ,基於React,dva.js,Ant Design

(1)其中dva主要是控制資料流向,是純粹的資料流,用作狀態管理

使用React技術棧管理大型複雜的應用往往要使用Redux來管理應用的狀態,然而隨著深度使用,Redux也暴露出了一些問題。dva 是一種改良Redux的架構方案,是基於現有應用架構 (redux + react-router + redux-saga 等)的一層輕量封裝,簡化了redux和redux-saga使用上的諸多繁瑣操作。

(2)ant design是一個基於react打造的一個服務於企業級產品的UI框架。

 2、umiJS是一個控制路由

以路由為基礎,用來控制路由

二、實踐分析

1、使用Ant Design pro腳手架官網來搭建專案,根據官網教程比較容易,

根據官網可知,使用ant design pro生成的專案目錄為:

其中最重要的四個資料夾,services、modles、mock、pages

  • sevices:資料介面
  • modles:資料處理
  • mock:模擬資料
  • pages:頁面

pages觸發modles中的方法來處理資料,若為非同步操作在modles中需要呼叫services中的資料介面方法,在後臺未寫完時可以通過mock中的模擬資料來除錯

具體來說,也即是使用dva時,資料流向或者說觸發流程為:在pages中的jsx檔案中通過dispatch觸發models中的js檔案中的effects或者reducers中的方法,其中effects中的方法是非同步操作,通過yield call(呼叫介面函式方法名)呼叫從services中js檔案引入的定義好的呼叫介面方法,然後通過yield put({type: 'reduceres中的方法'});來觸發 reducers中的方法來修改state。

資料流向圖如下:

資料的改變發生通常是通過:

  • 使用者互動行為(使用者點選按鈕等)
  • 瀏覽器行為(如路由跳轉等)觸發的

當此類行為會改變資料的時候可以通過 dispatch 發起一個 action,如果是同步行為會直接通過 Reducers 改變 State ,如果是非同步行為(副作用)會先觸發 Effects 然後流向 Reducers 最終改變 State 。

 簡單的例項如下:

1、welcome.jsx檔案

import React from 'react';
import { Form, Input, Button, InputNumber } from 'antd';
import { connect } from 'dva';

//將form注入到props中
@Form.create()

//將models中的狀態state繫結到props中,解構出myInfo,以data命名繫結到props上
@connect(({lhj:{myInfo}})=>({ //箭頭函式返回一個物件,必須在物件外面加上一個括號
  myInfo
}))

class Welcome extends React.Component{
  handleSubmit = e=>{
    const { form, dispatch } = this.props;
    e.preventDefault();
    //校驗輸入域的值
    form.validateFields((err,values) =>{
      if(!err){
        console.log(values);
        //驗證成功 傳入物件{type: 'lhj/check',payload: {...values,}},呼叫lhj中的check函式,
        dispatch({
          type: 'lhj/check',
          payload: {
            ...values,
          }
        });
      }
    })
    //console.log('submit',form.getFieldValue('username'));
  }
  handleReset = ()=>{
    this.props.form.resetFields();
  }
  render(){
    const { getFieldDecorator } = this.props.form;
      return (
          <div>
              <Form onSubmit={this.handleSubmit} layout="inline">
                <Form.Item label="姓名">
                  {getFieldDecorator('username', {
                    rules: [{required: true, message: 'please input your username'}]
                  })(<Input placeholder="username"/>)}
                </Form.Item>
                <Form.Item label="年齡">
                  {getFieldDecorator('age',{
                    rules: [
                      // {type: 'number', message: 'this must be a number'},
                      {required: true, message: 'please input your age'}
                    ]
                  })(<InputNumber placeholder="age"/>)}
                </Form.Item>
                <Form.Item>
                  <Button type="primary" htmlType="submit">查詢</Button>
                </Form.Item>
                <Form.Item>
                  <Button onClick={this.handleReset}>取消</Button>
                </Form.Item>
              </Form>
            {this.props.myInfo.username}-{this.props.myInfo.age}
          </div>

      );
  }
}

export default Welcome;

2、services/lhj.js檔案

import request from '@/utils/request';
export async function lhjCheck(params){
    console.log(params,'services')
    return request('/api/lhj', { params });
}

3、models/lhj檔案

import {lhjCheck} from '@/services/lhj';
const lhjModel = {
    namespace: 'lhj',
    state: {
        myInfo: {
            username: '',
            age: 0,
        }
    },
    effects: {
        *check({ payload },{ call, put }){
           // console.log(payload,'lhj/check');
            const res = yield call(lhjCheck, payload);
           // console.log(res,'res');//res為從mock中返回的虛擬資料
            yield put({
                type: 'checkInfo',
                payload: { myInfo: res },
            })

        },
    },
    reducers: {
        checkInfo(state, { payload }){
             console.log(state,payload,'checkInfo');
            return {
                ...state,
                ...payload,//同名的會覆蓋掉
            }
        },
        saveInfo(state){
            return {
                
            }
        },
    }
}

export default lhjModel;

4、mock/lhj.js檔案

export default {
    'Get /api/lhj': {
        username: 'lhj',
        age: 24
    },
}

三、幾個知識點總結:

1、connect的作用是將元件和models結合在一起。將models中的state繫結到元件的props中。並提供一些額外的功能,譬如dispatch。通過connect來繫結繫結model state。意味著Component裡可以拿到Model中定義的資料,Model中也能接收到Component裡dispatch的action。實現了Model和Component的連線。注意@connect必須放在export default class前面

2、dispatch 函式,通過 type 屬性指定對應的 actions 型別,而這個型別名在 reducers(effects)會一一對應,從而知道該去呼叫哪一個 reducers(effects),除了 type 以外,其它物件中的引數隨意定義,都可以在對應的 reducers(effects)中獲取,從而實現訊息傳遞,將最新的資料傳遞過去更新 model 的資料(state)

當在元件裡發起action時,直接dispatch就行了(

dispatch({
            type: `monthCard/query`,
            payload: {}//需要傳遞的資料
        })

),dva會幫你自動呼叫effects/reducers。當發起同步action時,type寫成'(namespace)/(reducer)'dva就幫你呼叫對應名字的reducer直接更新state,當發起非同步action,type就寫成'(namespace)/(effect)',dva就幫你呼叫對應名字的effect,然後通過yield put呼叫reducer來實現非同步更新state

3、專案的開發流程一般是從設計model state開始進行抽象資料,完成component後,將元件和model建立關聯,通過dispatch一個action,在reducer中更新資料完成資料同步處理;當需要從伺服器獲取資料時,通過Effects資料非同步處理,然後呼叫Reducer更新全域性state。是一個單向的資料流動過程。

相關文章