React - hooks + hoc 實現權限校驗系統(按鈕、頁面等權限)

前置條件

  1. react,這裏使用 umiJs腳手架
  2. 使用redux數據流,這裏使用 dvaJS數據流
  3. 建立頁面 「TestPage」,做爲例子頁面
  4. 建立按鈕組件「MyInput」,做爲例子按鈕

部分代碼目錄

Demo/
    node_modules/
    dist/
    src/
        components/
            MyInput/
                index.js // 公共組件,input
            HOCAuth/
                index.js // 核心權限校驗組件
        pages/
            test/
                index.js // 咱們的測試頁面
                model.js // test頁面的狀態
            home/
                index.js // home 頁面
                model.js // home 頁面的狀態
        models/
            global.js // 最頂層的全局公共狀態
        services/ // api等等
        utils/
        app.js // 入口函數
    router.js // 路由配置
    package.json
    ...等等

思路

如何校驗權限?
咱們將須要校驗的(按鈕或頁面等)目標組件,經過一個公共組件包裹(即hoc組件),在這個hoc組件中判斷目標組件的權限編碼是否存在於權限表裏,「若存在」則當前有權限訪問,渲染。「不存在」則返回 nullnode

那麼,咱們首先要儲存一份權限表,供全部組件使用。再爲每一個組件設置對於的權限編碼。react

這裏咱們對頁面的權限編碼配置規則爲 '數字-數字',如:'1-2'、'1-3'等等。頁面級組件使用'-'鏈接。
按鈕級的權限編碼爲:'1-1_1'、'1-1_2'等等。 按鈕級組件使用'_'鏈接。
如咱們當前 test 頁面編碼爲 '1-1',且該下面也有兩個按鈕級組件,那麼該組件編碼分別爲 '1-1_1'、'1-1_2'。json

例子:
const auth = {
    '1-1': true,
    '1-1_1': true
} // 權限表

const testPageAuthKey = '1-1' // test頁面的權限編碼
const inputAuthKey = '1-1_1' // test頁面下的input組件權限編碼

若 auth[authKey] === true 即有權限,渲染對應組件

接下來定義狀態:redux

每一個頁面有單獨的 model.js(即redux中的store),用於存放該頁面的狀態。
global.js 存放項目最頂層的狀態,爲公共狀態。api

global 中儲存一份權限表 auth,爲全部按鈕或頁面的權限。渲染按鈕或頁面前,校驗當前是否有權限,無權限則返回 nullapp

例子
// global.js
const Model = {
    namespace: 'Global',
    
    state: {
        auth: {
            '1-1': true, // 表示擁有test頁面權限
            '1-1_1': true, // 表示擁有test頁面下的input組件權限
        } // 當前全部的權限
    },
    effects: {
        * fetchAuth({ payload, callback }, { call, put }) {
            // 登陸後調用api獲取當前用戶所擁有的權限配置,更新掉auth
            const { auth } = yield call(apiFetchAuthFromServe, payload)
            yield put({
                type: 'save',
                payload: {
                    auth
                },
            }); 
            if (callback) callback();
        }
    },
    reducers: {
        save (state, { payload }) {
            return {
                ...state,
                ...payload,
            }
        }; 
    },
}

components/MyInput/index.js,input組件函數

import React, { useRef, useMemo, memo } from 'react';
import HOCAuth from '../HOCAuth';
const Input = props => {
    const {
        onChange,
        value,
        defaultValue,
    } = props;
    
    const input = useRef(null);
    
    const cur = useMemo(() => {
        if (value) return value;
        if (defaultValue) return defaultValue;
    }, [defaultValue, value]);
    
    function onInputChange (e) {
        if (onChange) onChange(e.target.value);
    }
    return (
        <input type="text" ref={ input } defaultValue={ cur } onChange={ onInputChange }/>
    );
};

export default memo(HOCAuth(Input)); // 這裏使用HOCAUth包裹 Input

再看看使用:測試

// test/index.js test頁面
import React from 'react';
import { connect } from 'dva';
import HOCAuth from '@/components/HOCAuth'
import MyInput from '@/components/MyInput'

const Test = props => {
    console.log(props)
    return (
        <div>
            <MyInput defaultValue={ 'default' } auth={ props.Global.auth } authKey={ '1-1_1' } /> // 傳遞authKey,表示該組件對應的權限編碼
        </div>
    );
};

function mapStateToProps ({ Global, Test }) {
    return {
        auth: Global.auth, // 訂閱global.js中的auth
        authKey: Test.authKey, // 當前test頁面的權限編碼,從model中獲取
        Test, // test/model.js
        Global
    };
}

export default connect(mapStateToProps)(HOCAuth(Test))
// 這是頁面級的權限校驗,使用 HOCAuth 包裹 Test

// test/model.js
const Model = {
    namespace: 'Test',
    
    state: {
        authKey: '1-1', // 當前test頁面的權限編碼
    },
    ...略
}

接下來是咱們的核心組件HOCAuth,components/HOCAuth/index.jsfetch

import React from 'react';

const HOCAuth = BaseComponent => (props) => {
    const { auth, authKey, ...others } = props;
    if (!auth || !authKey) return null;
    return (
        auth[authKey] ?
        <BaseComponent { ...others }/> : null // 過濾掉 auth與authKey
    );
};

export default HOCAuth;
// 簡單不?
以上爲react hooks + hoc實現的權限校驗系統簡單例子。歡迎方案溝通、指正

結束。

相關文章
相關標籤/搜索