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 是必备的一个字段,用来标识类型。

//在页面中可引入这个函数并调用,产生新的state
export function GetUserDetail(userDetail,totalElements,currentPage){
    return{
        type: GET_USER_DETAIL,
        userDetail,totalElements,currentPage
    }
}

Reducer 实际上就是一个函数,需要传入两个参数 state action,用来修改store的状态。本课程新建一个rootReducer.js来统一管理

//定义初始state
var init={
    userDetail:[],//保存从后台传递的数据
    usercount: 0,
    totalElements:0,
    currentPage:0,
    userOne:'',
};
export default function user(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。

// 引入总的rootReducer
import 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 react-router@3.0.5 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": "123456@qq.com",
      "password": "000000",
      "user_type": 2,
      "id": 1
    },
    {
      "id": 2,
      "name": "王二麻子",
      "age": 18,
      "email": "123@qq.com",
      "user_type": 0,
      "username": "admin1",
      "password": 123456789
    },
    {
      "name": "张三",
      "username": "admin3",
      "email": "123@qq.com",
      "password": "000000",
      "user_type": 2,
      "id": 3
    },
    {
      "name": "admin",
      "username": "admin4",
      "email": "123@123456.com",
      "password": "000000",
      "user_type": 0,
      "id": 4
    },
    {
      "name": "aaaa",
      "username": "aaaa",
      "email": "aaa@11.com",
      "password": "222222",
      "user_type": 0,
      "id": 5
    },
    {
      "name": "ffff",
      "username": "222@qq.com",
      "email": "222@qq.com",
      "password": "000000",
      "user_type": 1,
      "id": 7
    }
  ]
}

5.6 antd axios 的简介及安装

Ant Design 简称antd,是蚂蚁金服开发并正在使用的一套企业级的前端设计语言和基于 React 的前端框架实现,用于构建丰富的交互式用户界面。其官网地址:https://ant.design/docs/react/introduce/.

axios 是一个基于Promise 的 HTTP 客户端,可同时在浏览器和 node.js 中使用。参考:https://www.npmjs.com/package/axios

$ npm install antd axios --save-dev

5.7 新建模板文件 index.html

$ cd build 
$ vi index.html

index.html

<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>React Test</title>
    </head>
    <body>
         <!--要插入React组件的位置-->
        <div id="content"></div>
        <!-- 引入打包后的文件(相对路径) -->
        <script src="/bundle.js"></script>
    </body
</html>

5.6 新建入口文件 index.js 并利用 react-router 构建本项目的路由

首先,本项目实现的页面包含:登录,首页,用户列表 三个页面,所以在构建路由时需要实现页面间的跳转。

$ cd app 
$ vi index.js

index.js

//引入react,react-dom
import React from 'react';
import { render } from 'react-dom';
// 引入React-Router模块
//引入react,react-dom
import 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

// 引入总的rootReducer
import 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";
//引入每个页面的reducer
import 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"
class User extends React.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 >
                        <Button onClick={()=>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 function GetUserDetail(userDetail,totalElements,currentPage){
    return{
        type:GET_USER_DETAIL,
        userDetail,totalElements,currentPage
    }
}
export function ascyGetDetails(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 function AddUser(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));
                }
            });
        }
    }
}

//点击编辑时获取每行数据
function getUserone(userOne){
    return{
        type:GET_USER_ONE,
        userOne
    }
}
export function userOneFun(id){
    return function (dispatch){
        Ajax.getAjax("http://localhost:3000/user/"+id,function(response){
            if(response.data){
                //将返回的每行数据传给getUserone
                dispatch(getUserone(response.data));
            }
        });
    }
}

//新增或编辑时控制弹出框的显示与隐藏,将状态值保存至modaldisplay中
export function showModal(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'
//初始state
let init={
    userDetail:[],
    totalElements:0,
    currentPage:0,
    userOne:'',
    modaldisplay:false
};
export default function user(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自主学习。

八、参考链接

Redux中文文档

antd参考文档

axiosAPI

展开阅读全文

没有更多推荐了,返回首页