1. 程式人生 > >React 全家桶構建後臺管理平臺

React 全家桶構建後臺管理平臺

React 全家桶實現後臺管理介面

一、實驗介紹

1.1 實驗內容

React 是一個 Facebook 和 Instagram 用來建立使用者介面的 JavaScript 庫。創造 React 是為了解決一個問題:構建隨著時間資料“不斷變化”的“大規模”應用程式。本課程雖然使用了前端框架 antd,從零開始構建一個 React 後臺管理介面,並結合 React+React-Router+React-Redux 實現頁面功能,加深對 React 全家桶的理解及運用。

1.2 實驗知識點

  • webpack 基礎配置及使用
  • React 構建專案流程
  • Redux 簡介及基礎使用
  • UI框架 antd 的基本使用
  • axios
    的基本使用
  • json-server 模擬後臺資料介面

1.3 實驗環境

  • node.js
  • Xfce終端

1.4 適合人群

本課程難度為一般,屬於初級級別課程,適合具有React基礎的使用者,熟悉React基礎知識加深鞏固。

1.5 程式碼獲取

你可以通過下面命令將程式碼下載到實驗樓環境中,作為參照對比進行學習。

$ wget http://labfile.oss.aliyuncs.com/courses/857/react.zip

程式碼下載完成後解壓並進入專案目錄執行一下命令就能專案就能跑起來,開啟瀏覽器輸入127.0.0.1:3005,就能看到效果

$ unzip react.zip$ cd react $ npm i   #這步較慢請耐心等待
$ npm run dev$ sudo npm install json-server -g$ npm run server

二、實驗原理

由於React 中元件間通訊是單向資料流, 當專案中元件巢狀複雜時,子元件向父元件通訊資料傳遞就變得非常複雜。所以 Fackbook 提出 Flux 來管理 React 的資料流,後續又出現不同的架構,通過對比發現 Redux 相對其他的更為簡化。但 Redux 和 React 是沒有必然關係的,Redux 僅僅是用於管理 state。

Redux 主要的組成部分為: Action,Reducer,Store。Redux 的執行流程:首先需要註冊一個全域性唯一的store物件,用來維護整個應用的state;當要變更state時,我們會dispatch一個action,reducer根據action更新相應的state。

Aciton 它可以理解為一個載體,是資料從應用傳遞到store的載體,其中 type 是必備的一個欄位,用來標識型別。

//在頁面中可引入這個函式並呼叫,產生新的stateexport functionGetUserDetail(userDetail,totalElements,currentPage){    return{        type: GET_USER_DETAIL,        userDetail,totalElements,currentPage    }}

Reducer 實際上就是一個函式,需要傳入兩個引數 state action,用來修改store的狀態。本課程新建一個rootReducer.js來統一管理

//定義初始statevar init={    userDetail:[],//儲存從後臺傳遞的資料    usercount: 0,    totalElements:0,    currentPage:0,    userOne:'',};export default functionuser(state=init,action){    switch(action.type){        //case 後的名稱必須與action中type保持一致        case GET_USER_DETAIL:            return Object.assign({},state,{userDetail:action.userDetail,totalElements:action.totalElements,currentPage:action.currentPage});        default :            return state;    }}

Store 是一個全域性物件,用來維護 state 狀態的,主要有兩個方法 store.getState() 獲取最近內部的 state,store.dispatch(action) 連線 action,reducer 與 state。

// 引入總的rootReducerimport rootReducer from "../reducers/rootReducer";// 引入redux,包含中介軟體import { createStore,applyMiddleware } from 'redux';import thunk from 'redux-thunk';const store=createStore(rootReducer, applyMiddleware(thunk));export default store;

React-Redux 是一個輕量級的庫,核心的方法只有 Provider 與 connect。 Provider 的功能主要包含以下兩點:

  • 包裹原應用元件的最外層,使整個應用成為成為其子元件
  • 接收 Redux 的 store 作為 props,通過context物件傳遞給子孫元件connect 是真正連結 React 和 Redux 的模組

三、開發準備

開啟Xfce終端,進入 Code 目錄,建立 react 資料夾, npm的下載速度較慢,我們修改npm源,這個步驟比較慢,請大家耐等待(如已經瞭解安裝的同學,可直接下載專案的package.json放到自己的專案,npm install),安裝完成之後cnpm -v 檢視是否安裝成功。

$ mkdir react && cd react$ sudo npm config set registry https://registry.npm.taobao.org$ sudo npm info underscore

初始化 package.json

執行以下命令後,一直按enter鍵,如果需要對於專案名稱,作者等資訊進行修改,根據提示做相應的操作。

$ npm init

安裝 webpack 並在根目錄下建立並配置 webpack.config.js 檔案

webpck 需要全域性和本地同時安裝。

$ sudo npm install webpack -g$ sudo npm install webpack --save-dev

webpack.config.js

var path = require('path');var webpack = require('webpack');//__dirname是node.js中的一個全域性變數,它指向當前執行指令碼所在的目錄module.exports = {    devtool: 'eval-source-map', //生成Source Maps,這裡選擇eval-source-map    entry:['webpack/hot/dev-server', path.resolve(__dirname, './app/index.js')], //唯一入口檔案    output: { //輸出目錄        path: __dirname + "/build", //打包後的js檔案存放的目錄        filename: 'bundle.js', //打包後的js檔名    },    module: {        loaders: [{            test: /\.jsx?$/,            exclude: /node_modules/, //遮蔽不需要處理的檔案(資料夾)(可選)            loader: 'babel-loader'        }, {            test: /\.css$/,            loader: 'style-loader!css-loader'        }, {            test: /\.less$/,            loader: 'style-loader!css-loader!less-loader'        }, {            test: /\.(png|jpg)$/,            loader: 'url-loader?limit=25000'        }]    },    plugins: [//熱重新整理        new webpack.HotModuleReplacementPlugin()    ],};

四、專案檔案結構

根據檔案結構新建初步專案目錄

$ mkdir app build$ cd app mkdir actions reducers components store style views
├── app                 原始碼目錄,在這個目錄下做開發│   ├── actions         儲存可以發出的 action│   │   ├── ajax.js     自主封裝ajax│   │   ├── login.js    控制登入驗證│   │   └── user.js     user的增刪改查獲取,彈出框控制action│   ├── components      普通元件目錄(如,彈出表單元件)│   │   └── User│   │       └── AlertUser.js   編輯新增彈出Form框元件│   ├── index.js        入口檔案,路由配置檔案│   ├── reducers        存放action的處理器reducers│   │   ├── rootReducer.js│   │   └── user.js│   ├── store           全域性 store 儲存目錄│   │   └── store.js│   ├── style           樣式目錄│   │   └── index.css│   └── views           容器元件存放目錄│       ├── Index.js│       ├── Login.js│       ├── Menu.js│       └── User.js├── build               打包後文件儲存目錄及模板檔案存放位置 │   ├── bundle.js│   └── index.html├── .babelrc            babel配置檔案(預設隱藏)├── db.json             模擬後臺資料├── package.json        npm配置檔案└── webpack.config.js   webpack配置檔案

五、實驗步驟

5.1 安裝 React 的系列依賴

本課程 react-router 的版本使用3.0.5,redux-thunk 一箇中間件,可以讓action建立函式先不返回一個action物件,而是返回一個函式,函式傳遞兩個引數(dispatch,getState),在函式體內進行業務邏輯的封裝。

$ sudo npm install --save-dev react react-dom redux react-redux [email protected] react-redux-router redux-thunk

5.2 安裝 Babel 並在根目錄下建立並配置 .babelrc 檔案

使用JSX,可以極大的簡化React元素的建立,其語法風格類似於HTML語法風格,讓習慣html的人更容易理解。但瀏覽器引擎並不能識別JSX語法,而 Babel 可以Jsx語法轉化為可是別的。這只是 Babel 的一個作用,它還會將ES6,ES7轉化為能識別的ES*。

$ sudo npm install --save-dev babel-core babel-loader  babel-preset-es2015 babel-preset-react

.babelrc (在react目錄下新建)

{    "presets":[        "es2015",        "react"    ]}

5.3 安裝 webpack 所需要的 loader

現今瀏覽器引擎不能是被 react 的 JSX 語法,需通過Babel

$ sudo npm install --save-dev babel-loader css-loader less-loader style-loader url-loader file-loader

5.4 安裝 webpack-dev-server

$ sudo npm install --save-dev webpack-dev-server

安裝完成後在 webpack.config.js 的 module 中新增devServer

devServer: {    contentBase: "./build", //預設webpack-dev-server會為根資料夾提供本地伺服器,本例項設定 build 目錄    historyApiFallback: true, //開發單頁應用時,如果設定為true,所有的跳轉將指向index.html    inline: true, //設定為true,自動重新整理頁面    port: 3001, //設定預設監聽埠,預設為"8080"}

需在package.json 檔案的 scripts 中新增 build 及 dev 以後直接使用 npm run dev 就能開啟頁面檢視實現效果,並能實現熱重新整理

 "scripts": {    "build": "webpack",    "dev": "webpack-dev-server --devtool eval --progress --colors --content-base build",  }

5.5 安裝並配置 json-server 模擬後臺資料介面

json-server 使用第三方庫真實化模擬資料,但是資料傳輸的埠及 config 檔案需要手動配置,這裡為了方便後續使用我們在 package.json 檔案的 scripts 中新增 server 後續使用npm run server 就能開啟後臺資料介面。

 "scripts": {    "server": "json-server db.json -w -p 3000"  }

終端執行

$ sudo npm install json-server --save-dev $ vi db.json

db.json

因為是使用者列表,所以初步設計的使用者資訊包含 id(唯一值),name,age,email,user_type(識別使用者身份,0-普通使用者,1-標準會員,2-高階會員)檔案

"user": [    {      "name": "大毛",      "username": "admin",      "email": "[email protected]",      "password": "000000",      "user_type": 2,      "id": 1    },    {      "id": 2,      "name": "王二麻子",      "age": 18,      "email": "[email protected]",      "user_type": 0,      "username": "admin1",      "password": 123456789    },    {      "name": "張三",      "username": "admin3",      "email": "[email protected]",      "password": "000000",      "user_type": 2,      "id": 3    },    {      "name": "admin",      "username": "admin4",      "email": "[email protected]",      "password": "000000",      "user_type": 0,      "id": 4    },    {      "name": "aaaa",      "username": "aaaa",      "email": "[email protected]",      "password": "222222",      "user_type": 0,      "id": 5    },    {      "name": "ffff",      "username": "[email protected]",      "email": "[email protected]",      "password": "000000",      "user_type": 1,      "id": 7    }  ]}

5.6 antd axios 的簡介及安裝

Ant Design 簡稱antd,是螞蟻金服開發並正在使用的一套企業級的前端設計語言和基於 React 的前端框架實現,用於構建豐富的互動式使用者介面。其官網地址:https://ant.design/docs/react/introduce/.

$ npm install antd axios --save-dev

5.7 新建模板檔案 index.html

$ cd build $ vi index.html

index.html

<!DOCTYPE html><html>    <headlang="en">        <metacharset="UTF-8">        <title>React Test</title>    </head>    <body>         <!--要插入React元件的位置-->        <divid="content"></div>        <!-- 引入打包後的檔案(相對路徑) -->        <scriptsrc="/bundle.js"></script>    </body</html>

5.6 新建入口檔案 index.js 並利用 react-router 構建本專案的路由

首先,本專案實現的頁面包含:登入,首頁,使用者列表 三個頁面,所以在構建路由時需要實現頁面間的跳轉。

$ cd app $ vi index.js

index.js

//引入react,react-domimport React from 'react';import { render } from 'react-dom';// 引入React-Router模組//引入react,react-domimport React from 'react';import { render } from 'react-dom';import {    Provider}from "react-redux";// 引入React-Router模組import { Router, Route, Link, hashHistory, IndexRoute } from 'react-router';import store from "./store/store";// 全域性引入Ant-Design樣式import "antd/dist/antd.min.css";//引入全域性樣式import './style/index.css'//引入自定義元件import Login from "./views/Login";//登入頁面import User from "./views/User"//使用者列表import Menu from "./views/Menu"//側邊欄選單import Index from "./views/Index"//歡迎頁面// 配置路由render((    <Provider store={store}>        <Router history={hashHistory}>            <Route path="/login" component={Login} />            <Route path="/" component={Menu} >                <IndexRoute component={Index}/>                <Route path="user" component={User} />            </Route>        </Router>    </Provider>),document.getElementById('content'));

5.6 構建頁面

本課程主要的頁面包含4個,登入頁面,選單頁,首頁及使用者列表頁面,頁面的程式碼實現都在views目錄下。主要的業務邏輯使用者列表,包含查詢,新增,編輯,刪除。而編輯與新建時彈出的模態框封裝在 components 目錄下.

首先我們需要構建一個全域性的store用於管理state,在app/store 目錄下建立 store.js

// 引入總的rootReducerimport rootReducer from "../reducers/rootReducer";// 引入redux,包含中介軟體import { createStore,applyMiddleware } from 'redux';import thunk from 'redux-thunk';const store=createStore(rootReducer, applyMiddleware(thunk));export default store;

在app/reducers構建一個總的reducer管理檔案rootReduce.js

import {    combineReducers} from "redux";//引入每個頁面的reducerimport user from "./user";var rootReducer=combineReducers({    user,});export default rootReducer;

做到這裡,我們就可以根據路由引入檔案在 view 目錄下編寫自己的頁面,如果需要有行為,如:增加,需在action目錄下建立,如頁面內需要使用到 state 資訊,需要reducers目錄對應建立,詳細需根據專案建立。以下是以編輯功能作為例項進行介紹。

User.js

import {    userOneFun,showModal,} from "../actions/user";import {    connect} from "react-redux";//引入彈出框Form表單import AlertUser from "../components/User/AlertUser"classUserextendsReact.Component{    //編輯使用者    toEdit(id) {        //獲取單行資料,儲存在userOne中        this.props.dispatch(userOneFun(id));        //顯示彈出框        this.props.dispatch(showModal(true));    }}  render() {        const columns = [{                title: '操作',                key: 'action',                render: (text, record) => (//record表示單行資料                    <span >                        <ButtononClick={()=>this.toEdit(record.id)}> 編輯 </Button>                    </span >                ),            }        ]        return(            <Layout>                <Content>                    {/* AlertUser元件 */}                    <AlertUser />                </Content>            </Layout>        )    }function select(state){    return{        userOne:state.user.userOne,    }}//匯出元件export default connect(select) (User);

actions user.js

//ajax是自主封裝的檔案import * as Ajax from './ajax';//定義常量export const GET_USER_DETAIL = "GET_USER_DETAIL"export const GET_USER_ONE = "GET_USER_ONE"export const GET_MODAL_SHOW = "GET_MODAL_SHOW"//獲取所有使用者列表export functionGetUserDetail(userDetail,totalElements,currentPage){    return{        type:GET_USER_DETAIL,        userDetail,totalElements,currentPage    }}export functionascyGetDetails(data){    return function (dispatch){        Ajax.getAjax("http://localhost:3000/user",function(response){            if (response.data) {                let number = 1;                if (data) {                    number = data.page                }                dispatch(GetUserDetail(response.data,response.data.length,number));            } else {                dispatch(GetUserDetail([],0,1));            }        });    }}//新增與修改使用者,通過有無id判斷是新增還是刪除export functionAddUser(data){    return function (dispatch){        if (data.id) {            Ajax.putAjax("http://localhost:3000/user/"+data.id,data,function(response){                if(response.data){                    //成功後重新整理頁面                    dispatch(ascyGetDetails());                    //成功後關閉form彈出框                    dispatch(showModal(false));                }            });        } else {            Ajax.postAjax("http://localhost:3000/user",data,function(response){                if(response.data){                    dispatch(ascyGetDetails());                    dispatch(showModal(false));                }            });        }    }}//點選編輯時獲取每行資料functiongetUserone(userOne){    return{        type:GET_USER_ONE,        userOne    }}export functionuserOneFun(id){    return function (dispatch){        Ajax.getAjax("http://localhost:3000/user/"+id,function(response){            if(response.data){                //將返回的每行資料傳給getUserone                dispatch(getUserone(response.data));            }        });    }}//新增或編輯時控制彈出框的顯示與隱藏,將狀態值儲存至modaldisplay中export functionshowModal(modaldisplay){    return{        type:GET_MODAL_SHOW,        modaldisplay    }}

reducers user.js 連結 action 和 store, 根據不同的action返回不同state

import { GET_USER_DETAIL, GET_USER_ONE,GET_MODAL_SHOW } from '../actions/user'//初始statelet init={    userDetail:[],    totalElements:0,    currentPage:0,    userOne:'',    modaldisplay:false};export default functionuser(state=init,action){    switch(action.type){        //使用者的所有資訊,用於開始的展示        case GET_USER_DETAIL:            return Object.assign({},state,{userDetail:action.userDetail,totalElements:action.totalElements,currentPage:action.currentPage});        //點選編輯時,取得當前使用者資訊        case GET_USER_ONE:            return Object.assign({},state,{userOne:action.userOne});        //控制彈出框的顯示與隱藏        case GET_MODAL_SHOW:            return Object.assign({},state,{modaldisplay:action.modaldisplay});        default :            return state;    }}

六、實驗總結

本課程基於 React 全家桶進行了簡單專案的構建,從零開始搭建專案不僅能回顧基礎知識,引入 Redux 也解決了我們單個 React 專案中的元件間通訊困難的問題,加深對 React 專案的理解及使用,學會使用 antd UI框架,能更快節省開發週期,本課程設計的 antd 元件較少,可以根據官網API自主學習。

八、參考連結