react技术栈构建后台管理系统模版

之前一直开发的技术栈主要是VueJS相关,平时也有阅读React文档,但是没有把React相关技术栈串联起来,形成一个后台系统的模板。在学习的过程之中,基于React开发推荐的create-react-app脚手架搭建管理系统模板。

开发依赖

antd: "^3.19.1",
axios: "^0.19.0",
bizcharts: "^3.5.3",
react: "^16.8.6",
react-dom: "^16.8.6",
react-redux: "^7.0.3",
react-router-dom: "^5.0.0",
react-transition-group: "^4.1.0",
redux: "^4.0.1"   

git仓库地址

React-admin-system

运行效果

开发这个管理系统主要目的是理清React-Router v4React-ReduxRedux等常用类库的布置和使用。在掘金浏览许多关于React技术开发的文章。关于管理系统对于用户登录权限认证和系统路由布置使用以及对ajax第三方类库二次封装等文章比较少。所以下面会比较着重描述一下个人开发过程中这部分的实现。

react技术栈构建后台管理系统模版_第1张图片
login

react技术栈构建后台管理系统模版_第2张图片
DataCount

react技术栈构建后台管理系统模版_第3张图片
progress

目录分析

开发对于请求使用的是第三方请求库axios,对于axios的封装主要在平时Vuejs开发时候对请求封装实践。开发主要部分是util/fakeAuth.jsrouter/PrivateRoute.js,这部分是对用户登录状态验证。而components/ContentMain是登录后的主要路由设置。

├─public(静态资源目录)
├─screenShot(开发现阶段运行截图)
├─service(service服务Koa)
│  ├─bin
│  ├─config
│  ├─controller
│  ├─model
│  ├─routes
│  └─util
└─src
    ├─api(请求二次封装)
    ├─assets(开发静态资源目录)
    │  └─images
    ├─components(图标类组件)
    │  ├─AreaMap
    │  ├─Chart
    │  ├─ContentMain
    │  ├─Diagram
    │  ├─Line
    │  ├─Map
    │  └─SiderNav(sider侧边导航栏)
    ├─redux(store组件)
    ├─router(路由组件)
    ├─util(权限验证函数)
    └─views(主要开发组件)
        ├─Alert
        ├─Avatar
        ├─Basic
        ├─Cascader
        ├─Checkbox
        ├─DataChart
        ├─Form
        ├─Index
        ├─Login
        ├─Message
        ├─NoMatch
        ├─Progress
        └─Spin

login用户登录状态验证

包装PrivateRoute权限路由

React-Router的路由组件Route,包装路由组件使需要登录获取权限的路由,需要自动认证再进行渲染。渲染组件需要通过权限认证函数fakeAuth.authenticate()进行验证,该函数会判别是否存在后端接口返回的token值,分别渲染不同组件。

import React from 'react';
import {Route,Redirect} from 'react-router-dom';
import {fakeAuth} from '../util/fakeAuth';
const PrivateRoute = ({component:Component,...rest})=>{
    return (
         (fakeAuth.authenticate())?():(
                
            )}
        >
    )
}
export default PrivateRoute;
fakeAuth验证函数

fakeAuth文件包含三个函数authenticatesetTokensignout,以上分别对应验证登录权限、设置登录token、清除登录token。

export const fakeAuth = {
    authenticate() {
        const token = sessionStorage.getItem("loginToken");
        return !!token ? true : false;
    },
    setToken(token) {
        sessionStorage.setItem("loginToken", token);
        return true;
    },
    signout() {
        sessionStorage.removeItem('loginToken');

    }
};
login登录验证详细

login.js通过fakeAuth.authenticate()验证,然后分别渲染不同组件。组件在这里主要有两个作用:

  • 用户登录获取权限路由权限后,在浏览器地址栏重新输入/login路由会自动返回权限路由路由首页。
  • 对于未登录用户,自动跳转到登录页。
import React,{Component} from 'react';
import {Redirect} from 'react-router-dom';
import {fakeAuth} from '../../util/fakeAuth';
import LoginForm from './index';
export default class Login extends Component{
    render(){
        return (
            fakeAuth.authenticate()?:
        )
    }
}
登录请求代码

登录认证请求代码在views/login/loginForm中,handleSubmit是登录事件函数,主要对获取用户权限接口获取token,然后进行路由跳转.this.props.history.pushReact-Router v4版本特有的写法,其他版本可以参考官方文档。要获取到this.props.history需要withRouter对组件传入location,match,history等信息。

    handleSubmit = e => {
        e.preventDefault();
        this.props.form.validateFields((err, values) => {
          if (!err) {
            //这里需要对后端接口请求,调试中
            fakeAuth.setToken("zxcvbnmasdfghjkl");
            this.props.history.push('/dataCount');
            message.success('登陆成功',1);
            return;
          }
        });
    }

App.js入口文件

login是公开的路由,其他需要权限的路由包含在PrivateRoute组件中,最后一个如果没有组件匹配,最后匹配的是我们自定义的404页面

import React from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {Provider} from 'react-redux';
import {store} from './redux/index.js';
import {CSSTransition} from "react-transition-group";
import Login from './views/Login/login';
import Index from './views/Index';
import PrivateRoute from './router/PrivateRoute';
import NoMatch from './views/NoMatch';
import history from './api/history';
import './App.css';
function App() {
  return (
    
      
          
); } export default App;

ContentMain权限路由路由配置页面

ContentMain主要是配置了权限路由的配置。使用PrivateRoute包装路由,方便性由此可见。配置路由没有比较难逻辑,如下所示:

import React,{Component} from 'react';
import {Switch,withRouter} from 'react-router-dom';
import PrivateRoute from '../../router/PrivateRoute';
import DataChart from '../../views/DataChart';
import Basic from '../../views/Basic';
import Form from '../../views/Form';
import Message from '../../views/Message';
import Alert from '../../views/Alert';
import Spin from '../../views/Spin';
import Progress from '../../views/Progress';
import Checkbox from '../../views/Checkbox';
import Cascader from '../../views/Cascader';
import NoMatch from '../../views/NoMatch';
import './index.css';
class ContentMain extends Component{
    render(){
        return(
            
) } } export default withRouter(ContentMain);

axios二次封装统一请求处理

api/index.js主要包含了对axios第三方请求库的二次封装,包含错误统一处理以及不同请求方法GET、POST、DELETE、PUT等统一风格的api。关于对token请求权限过期,返回请求状态码401,清除token,重定向到/logn处理逻辑也会在这里。在这一部分,Vuejs的处理逻辑也很类似,但是比较熟悉可以直接通过以下方式进行重定向:

import router from "../router/index.js";
router.replace({
    path: "/login",
    query: {
        redirect: router.currentRoute.path
    }
});

但是对于React-Router,网上浏览比较多的文章,尝试多比较多遍,都没有找到一个不是强制刷新的路由方案,使用window.location.href可以强制跳转,但是这里使用了createBrowserHistory方法进行重定向。如果有其他的方案可以给我留言。菜鸡的我才能茁壮成长。下面是关于封装的代码部分:

import axios from "axios"; 
import {fakeAuth} from '../util/fakeAuth';
import {message as Message} from 'antd';
import {timeout,baseURL} from "./config.js";
import history from './history';
axios.defaults.timeout = timeout;
axios.defaults.baseURL = baseURL;
axios.interceptors.request.use(
    config => {
        if (fakeAuth.authenticate()) {
            config.headers.Authorization = `Bearer ${sessionStorage.getItem('loginToken')}`;
        }
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);
axios.interceptors.response.use(
    response => {
        return response;
    },
    error => {
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    fakeAuth.signout();
                    history.push('/login');
                    break;
                default:
            }
            const message = error.response.data.message ?error.response.data.message :"服务器异常";
            Message.error(message);
        }
        return Promise.reject(error);
    }
);
const gl_ajax = params => {
    return axios({
            method: params.method.toLowerCase(),
            url: `${axios.defaults.baseURL}${params.url}`,
            data: params.method !== "get" ? params.data : "",
            params: params.method === "get" ? params.data : "",
            responseType: params.file ? "blob" : ""
        })
        .then(res => {
            params.success && params.success(res);
        })
        .catch(err => {
            params.error && params.error(err);
        });
};
export default gl_ajax;

history文件部分是参考了网友给的技术方案,利用了createBrowserHistory({forceRefresh:true}),这里show出来给大家参考一下:

// history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory({forceRefresh:true}); 

// config.js
export const timeout = 5000;
export const baseURL =
  process.env.NODE_ENV === "production"
    ? "https://echo/api/v1"
    : "http://localhost:8080/api/v1";

如果觉得喜欢可以给个小星星(star)吗?

React-admin-system

参考文章

[译] 2019 React Redux 完全指南

[译]React中的用户认证(登录态管理)

React Router 4.x开发,这些雷区我们都帮你踩过了

你可能感兴趣的:(react技术栈构建后台管理系统模版)