React技術棧構建後臺管理系統模版

以前一直開發的技術棧主要是VueJS相關,平時也有閱讀React文檔,可是沒有把React相關技術棧串聯起來,造成一個後臺管理系統的模板。在學習的過程之中,基於React開發推薦的create-react-app腳手架搭建管理系統模板。css

開發依賴

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-systemvue

運行效果

開發這個管理系統主要目的是理清React-Router v4React-ReduxRedux等經常使用類庫的佈置和使用。在掘金瀏覽許多關於React技術開發的文章。關於管理系統對於用戶登陸權限認證和系統路由佈置使用以及對ajax第三方類庫二次封裝等文章比較少。因此下面會比較着重描述一下我的開發過程當中這部分的實現。react

login

dataCount

progress

404

目錄分析

開發對於請求使用的是第三方請求庫axios,對於axios的封裝主要在平時Vuejs開發時候對請求封裝實踐。開發主要部分是util/fakeAuth.jsrouter/PrivateRoute.js,這部分是對用戶登陸狀態驗證。而components/ContentMain是登陸後的主要路由設置。ios

├─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值,分別渲染不一樣組件。git

import React from 'react';
import {Route,Redirect} from 'react-router-dom';
import {fakeAuth} from '../util/fakeAuth';
const PrivateRoute = ({component:Component,...rest})=>{
    return (
        <Route
            {...rest}
            render = {props => (fakeAuth.authenticate())?(<Component {...props}/>):(
                <Redirect to={{
                    pathname:"/login",
                    state:{from:props.location}
                }}/>
            )}
        ></Route>
    )
}
export default PrivateRoute;
複製代碼
fakeAuth驗證函數

fakeAuth文件包含三個函數authenticatesetTokensignout,以上分別對應驗證登陸權限、設置登陸token、清除登陸token。github

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()驗證,而後分別渲染不一樣組件。<Redirect>組件在這裏主要有兩個做用:ajax

  • 用戶登陸獲取權限路由權限後,在瀏覽器地址欄從新輸入/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()?<Redirect to="/"></Redirect>:<LoginForm />
        )
    }
}
複製代碼
登陸請求代碼

登陸認證請求代碼在views/login/loginForm中,handleSubmit是登陸事件函數,主要對獲取用戶權限接口獲取token,而後進行路由跳轉.this.props.history.pushReact-Router v4版本特有的寫法,其餘版本能夠參考官方文檔。要獲取到this.props.history須要withRouter對組件傳入location,match,history等信息。vue-router

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頁面redux

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 (
    <Provider store={store}>
      <Router basename="/echo" history={history}>
          <div className="entryWrap">
              <CSSTransition
                classNames="fade"
                timeout={1000}
              >
                <Switch>
                  <Route path="/login" component={Login} exact/>
                  <PrivateRoute path="/" component={Index}/>
                  <Route component={NoMatch}/>
                </Switch>
              </CSSTransition>
          </div>
      </Router>
    </Provider>
  );
}
export default App;
複製代碼

ContentMain權限路由渲染頁面

ContentMain主要是配置了權限路由的配置。使用PrivateRoute包裝路由,方便性因而可知。配置路由沒有比較難邏輯,以下所示:axios

import React,{Component} from 'react';
import {Switch,withRouter,Route} from 'react-router-dom';
import PrivateRoute from '../../router/PrivateRoute';
import {routes} from '../../router/route';
import NoMatch from '../../views/NoMatch';
import './index.css';
class ContentMain extends Component{
    render(){
        return(
            <div className="routeWrap">
                <Switch>
                    {
                        routes.map(item=>{
                            return (
                                item.path?<PrivateRoute path={item.path} exact component={item.component}/>:<Route component={NoMatch}/>
                            )
                        })
                    }
                    
                </Switch>
            </div>
        )
    }
}
export default withRouter(ContentMain);
複製代碼

權限route路由配置

上面權限路由全部配置在router/route中,有點相似於vue-router的配置方式。

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';
export const routes = [
    {
        path: '/dataCount',
        component: DataChart
    },
    {
        path: '/basic',
        component: Basic
    },
    {
        path: '/form',
        component: Form
    },
    {
        path: "/alert",
        component: Alert
    },
    {
        path: '/message',
        component: Message
    },
    {
        path: '/spin',
        component: Spin
    },
    {
        path: '/progress',
        component: Progress
    },
    {
        path: '/checkbox',
        component: Checkbox
    },
    {
        path: '/cascader',
        component: Cascader
    }]
複製代碼

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";
複製代碼

登陸token過時處理

redux之類的第三方存儲,不須要藉助router, 只要收到401請求的時候, 修改redux auth.isTokenTimeout爲 true, 界面就跳到超時登錄了, 並且url沒改動,這樣登錄成功後界面還能依據url自動還原。

上面token過時路由跳轉方案是在react-china論壇一位網友提出,感受很不錯。解決方案地址

export const AuthorizeApplication = connect(x=> x.auth)(function Authorize({isLogin, isTokenTimeout}){
    if (isTokenTimeout) { return <TokenTimeoutSign /> }
    if (!isLogin) { return <Sign /> }
    return <Application />
})
複製代碼

若是以爲喜歡能夠給個小星星(star)嗎?

React-admin-system

參考文章
[譯] 2019 React Redux 徹底指南
[譯]React中的用戶認證(登陸態管理)
React Router 4.x開發,這些雷區咱們都幫你踩過了

相關文章
相關標籤/搜索