使用UmiJS框架開發React應用


1)、簡介

UmiJS讀音:(烏米)
UmiJS是一個可插拔的企業級React應用框架。官網地址是:https://umijs.org/zh/

特點:

  • 插件化
    umi的整個生命周期都是插件化的,甚至其內部實現就是由大量插件組成,比如:pwa、按需加載、一鍵切換 preact、一鍵兼容 ie9 等等,都是由插件實現。

  • 開箱即用
    你只需一個umi依賴就可啟動開發,無需安裝reactpreactwebpackreact-routerbabeljest等等。

  • 約定式路由
    類似next.js的約定式路由,無需再維護一份冗余的路由配置,支持權限、動態路由、嵌套路由等等。

2)、安裝

2.1)、安裝 nodejs

要使用UmijS首先要安裝nodejs環境,在Mac下安裝nodejs

    brew install nodejs

windows下安裝,需要到官網下載安裝程序,然后下一步下一步完成即可,也非常簡單。這里不介紹了,也可自行百度,網上有很多。

2.2)、安裝 yarn

可以把yarn看做了優化了的npm,其中tyarn使用的是npm.taobao.org的源,速度要快一些。平常使用的話使用tyarn即可。

npm i yarn tyarn -g --registry=https://registry.npm.taobao.org

2.3)、安裝 umi

tyarn global add umi

查看是否安裝成功:

umi -v

如果出現 'umi' 不是內部或外部命令,也不是可運行的程序 或批處理文件或者提示 umi: command not found

3)、使用 umi

3.1)、創建項目

mkdir ~/Documents/umi-demo

3.2)、初始化

進入到項目文件夾下

cd ~/Documents/umi-demo

再創建umi其他默認的目錄,這些默認的目錄名字不能寫錯。

mkdir -p {config,mock,src/pages,src/models,src/layouts}

config/: 該目錄下的config.js默認是全局的配置
mock/: 模擬后端請求數據的js目錄
src/: 代碼目錄
pages/: 為前端頁面, 頁面的后綴名可以是.js或者.jsx
models/: 為數據層, 處理數據的 js 文件
layouts/: 默認是整個項目的基礎布局文件

通過初始化命令將生成package.json文件,它是NodeJS約定的用來存放項目的信息和配置等信息的文件。

tyarn init -y

為項目設置一個默認的展開頁面,因為umiJS在后台啟動時會默認加載src/pages/index.js文件。使用下面命令可以通過umi命令創建index.js文件。

umi g page index

可以看到在pages下創建好了index.js和index.css文件。

3.3)、開發工具打開

1

目錄結構

2

3.4)、運行項目

umi dev

3

訪問: http://localhost:8000

4)、分層開發

4.1)、過程圖示

5

說明:

上圖中,左邊是用戶,中間為前端,右邊為后端。我們對前端進行分層,可以分為PageModelService3層。

  • Page 負責與用戶直接打交道:渲染頁面、接受用戶的操作輸入,側重於展示型交互 性邏輯。
  • Model 負責處理業務邏輯,為 Page 做數據、狀態的讀寫、變換、暫存等。
  • Service 負責與 HTTP 接口對接,進行純粹的數據讀寫。

其中 Page層通過UmiJSumi-plugin-react插件的dva功能,可以調用Model層定義的數據和方法;Model層通過import定義的異步請求函數request.js來調用Service層;而Service層就是去后端請求數據。

4.2)、開始開發

4.2.1)、添加依賴

添加umi的依賴

tyarn add umi --dev

添加umi-plugin-react插件

tyarn add umi-plugin-react --dev

添加.gitignore文件

node_modules
dist
.umi

config/config.js配置中引入umi-plugin-react插件

export default { 
    plugins: [ 
        ['umi-plugin-react', { 
            dva: true,
            antd: true
            
        }] 
    ] 
}; 

4.2.2)、antd基本布局

添加基本布局和樣式:
layouts文件目錄下創建index.js文件,在index.js中我們寫入:

import { Component } from 'react';
import { Layout } from 'antd';

// Header, Footer, Sider, Content組件在Layout組件模塊下
const { Header, Footer, Sider, Content } = Layout;

class BasicLayout extends Component {
    render() {
        return (
            <Layout>
                <Sider width={256} style={{ minHeight: '100vh', color: 'white' }}>
                    Sider
                </Sider>
                <Layout >
                    <Header style={{ background: '#fff', textAlign: 'center', padding: 0 }}>Header</Header>
                    <Content style={{ margin: '24px 16px 0' }}>
                        <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
                            {this.props.children}
                        </div>
                    </Content>
                    <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
                </Layout>
            </Layout>
        )
    }
}

export default BasicLayout;

上面代碼中,我們創建了一個三部分的基本布局:Header 、Content 、Footer。然后我們將 Content 替換成 { this.props.children },這樣之后我們設置的路由會通過替換 children 變量實現內容的切換。

上面需要引入的組件都安裝好了之后,我們就可以來編寫我們的前端代碼了。我們可以根據上面的圖,按照從下到上的順序進行編寫,也就是ServiceModelPage來進行。

4.2.3)、Service異步請求數據

在 src 目錄下創建 utils 目錄, 創建 request.js 文件

function checkStatus(response) {
    if (response.status >= 200 && response.status < 300) {
        return response;
    }
    const error = new Error(response.statusText);
    error.response = response;
    throw error;
}
/**
 * Requests a URL, returning a promise.
 *
 * @param {string} url The URL we want to request
 * @param {object} [options] The options we want to pass to "fetch"
 * @return {object} An object containing either "data" or "err"
 */
export default async function request(url, options) {
    const response = await fetch(url, options);
    checkStatus(response);
    return await response.json();
}

4.2.4)、Mock模擬數據

在 mock目錄下創建UserList.js文件,用來模擬數據。因為有了umi默認集成了mock功能,所以只要編寫mock數據即可。

export default {
    'get /ds/list' : function (req, res) {
        res.json({
            data: ['zhangsan','lisi','wangwu']
        })
    }
}

4.2.5)、Model層中引入該 js 文件用於異步請求

import request from '../../utils/request'

export default {
    namespace: 'user',
    //該模型中的一些屬性
    state: {
        data: []
    },
    //一些正常的同步方法
    reducers: {
        //state是原先的數據,result是effets中異步調用返回的數據
        save(state, result){
            //如果 result.data中存在數據,表示該函數是被異步調用初始化。直接返回
            if (result.data){
                return result.data;
            }
            let list = [...state.data, 'freeman'];
            //返回更新后的state對象
            return {
                data: list
            }
        }
    },
    effects: {
        // 這里定義異步方法
        *initData(params, sagaEffects) { //定義異步方法
            const {call, put} = sagaEffects; //獲取到call、put方法
            const url = "/ds/list"; // 定義請求的url
            let result = yield call(request, url); //執行請求
            yield put({ // 調用reducers中的方法
                type : "save", //指定方法名
                data : result  //傳遞ajax回來的數據, 注意 put 會指定調用的同步方法[reducers 中定義的方法],
                //該調用的方法會在定義的方法的入參添加一個參數(result), 使用該參數才能獲取到put方法,取到的值
            });
        }
    }

}

DVA 的 model 對象有幾個基本的屬性,需要大家了解。

  • namespacemodel 的命名空間,只能用字符串。一個大型應用可能包含多個 model,通過namespace區分。
  • state:當前 model 狀態的初始值,表示當前狀態。
  • reducers:用於處理同步操作,可以修改 state,由 action 觸發。reducer 是一個純函數,它接受當前的 state 及一個數據體(payload)作為入參,返回一個新的 state
  • effects:用於處理異步操作(例如:與服務端交互)和業務邏輯,也是由 action 觸發。但是,它不可以修改 state,要通過觸發 action 調用 reducer 實現對 state 的間接操作。
  • action:是 reducerseffects 的觸發器,一般是一個對象,形如{ type: 'add', payload: todo },通過 type 屬性可以匹配到具體某個reducer 或者 effectpayload 屬性則是數據體,用於傳送給 reducereffect

4.2.6)、Page層引入Model層的數據和方法

dva是基於 redux、redux-saga 和 react-router 的輕量級前端框架。官 網:https://dvajs.com/

@connect(mapStateToProps, mapDispatchToProps) 需要2個參數:

  • mapStateToProps:是一個方法,該方法的返回值是一個屬性對象{},它的作用是將這個包含state屬性的對象注入到this.props中。組件通過this.props.xx的方式即可獲取到model中的數據。

    • ① 、umi框架啟動,會自動讀取models目錄下所有model文件,(如:user/List.js中的數據 )
    • ②、這些model數據 會進入到mapStateToProps方法中
    • ③、在全局的數據中,會有很多,所以需要通過namespace進行區分,所以通過state[namespace]進行獲取數據
    • ④、拿到model數據中的data,也就是['zhangsan','lisi','wangwu']數據,進行包裹{}后返回
    • ⑤、返回的數據,將被封裝到this.props中,所以通過this.props.listData即可獲取到 model中的數據。
  • mapDispatchToProps: 是一個方法,它的返回值是一個函數對象{}, 它的作用是將這些函數注入到this.props中。

    • ①、所以可以把Model中暴露的方法綁定到當前的組件中,定義一個方法接收,然后可以綁定到onClick事件上,就可以實現點擊操作;也可以在頁面加載完的時候拿到數據對頁面進行渲染的操作(只需要綁定到生命周期函數上即可)。
    • ②、dispatch 函數就是和 dva model 打交道的唯一途徑。 dispatch 函數接受一個 對象 作為入參,在概念上我們稱它為 action,唯一強制要包含的是 type 字段,string 類型,用來告訴 dva 我們想要干什么。我們可以選擇給 action 附着其他字段,這里約定用 payload字段表示額外信息。

pages目錄下新建user/List.js(或List.jsx)頁面,使用快捷鍵rccrccp可以快速生成react組件。

import React, {Component} from 'react';
import { connect } from 'dva';
const namespace = 'user';

const mapStateToProps = (state)=>{
    let listData = state[namespace].data;
    return {listData}
};

const mapDispatchToProps = (dispatch) => {
    // 定義方法,dispatch是內置函數
    return { //返回的這個對象將綁定到this.props對象中
        addUser : () =>{
            // 定義方法
            dispatch({ // 通過調用dispatch()方法,調用model中reducers的方法
                type: `${namespace}/save` // 指定方法,格式: namespace/方法名
            });
        },
        userList : () => { //新增初始化方法的定義
            dispatch({
                type: `${namespace}/initData`
            });
        }
    }
}
@connect(mapStateToProps, mapDispatchToProps)
class List extends Component {

    componentDidMount() {
        this.props.userList();
    }

    render() {
        return (
            <div>
                <ul>
                    {
                        this.props.listData.map(
                            (v, i) => {return <li key={i}>{v}</li>}
                        )
                    }
                </ul>
                <button onClick={() => {this.props.addUser()}}>
                    添加
                </button>
            </div>
        );
    }
}

export default List;

4.3.)、umi-plugin-react插件升級

在運行 umi devumi build 運行或部署應用是,有時候會出現 “Path must be a string”錯誤。解決方法:

按照官網升級umi-plugin-react的版本。

  • ①、 package.json文件
{
  "devDependencies": {
-   "umi-plugin-react": "^1"
+   "@umijs/preset-react": "^1"
  }
}
  • ②、 config/config.js文件
export default {
- plugins: [
-   ['umi-plugin-react', {
-     dva: {},
-     antd: {},
-     ...
-   }]
- ],
+ dva: {},
+ antd: {},
+ ...
}

可以參考:https://umijs.org/docs/upgrade-to-umi-3#升級-umi-plugin-react-為-umijspreset-react

項目地址: https://gitee.com/zhaoxxnbsp/umi-demo.git

返回頂部↑


免責聲明!

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



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