dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)
【React系列】手把手帶你擼后臺系統(Redux與路由鑒權)
來源:https://juejin.im/post/5d9b5ddee51d45781b63b8f7
上一篇我們介紹了系統架構,這一篇將繼續介紹:
- Redux的應用
- 登錄授權
- 路由鑒權
二、Redux應用
側邊導航欄(Sidebar)我們實現了根據配置渲染菜單項,現在我們要繼續完善它的功能:導航高亮與鑒權。我們通過redux管理我們Sidebar的狀態,想要redux的store可用,我們必須使用它的和connect():
// Page.jsimport { createStore } from 'redux'import store from 'store' // 新建store目錄ReactDOM.render(, document.getElementById('root'))復制代碼的作用是讓store在整個App中可用,connect()的作用是將store和component連接起來。
// Sidebar.jsimport { connect } from 'react-redux'import { updateSidebarState } from 'store/action'class Sidebar extends Component { // 省略代碼...}const mapStateToProps = (state, owns) => ({ sidebar: prop('sidebarInfo', state), // 從store中取出sidebarInfo數據 ...owns})const mapDispatchToProps = dispatch => ({ dispatchSideBar: sidebar => dispatch(updateSidebarState(sidebar)) // 更新數據狀態})export default connect( mapStateToProps, mapDispatchToProps)(SideBar)復制代碼2.1 初始化Sidebar數據
初始化Sidebar數據主要做兩點:
- 默認的路由配置數據里面沒有標識高亮狀態,初始化過程增加active標志位;
- 為父級導航項增加key值標志位,用于檢測收合狀態;
經處理后的路由配置數據新增了active和key兩個屬性:
2.2 檢測高亮渲染側邊導航欄過程需要檢測高亮狀態:根據當前路由path與導航項的key值相比較:
// Sidebar.jsclass Sidebar extends Component { constructor(props) { // ... this.state = { routeName: path(['locaotion', 'pathname'], this.props), // 獲取當前路由信息 routes: compose(this.checkActive.bind(this), prop('sidebar'))(this.props) // 返回檢測后的路由數據 } } // 省略代碼... checkActive (arr, routeName='') { const rName = routeName || path(['location', 'pathname'], this.props) if(!rName) return arr return map((each) => { const reg = new RegExp(rName) if(reg.test(each.key)) { each.active = true } else if (each.routes) { each.routes = this.checkActive(each.routes, rName) } return each }, arr) }}export default connect( mapStateToProps, mapDispatchToProps)(withRouter(SideBar))復制代碼特別注意: Sidebar組件需要經由withRouter包裹后才能在組件內獲取路由相關信息。
三、登錄授權
這里設定的場景是:用戶的登錄數據在當前會話期內有效(sessionStorage存儲用戶信息),用戶信息全局可用(redux管理)。假定我們存儲的用戶數據有:
{ username: '', // 帳號 permission: [], // 用戶權限列表 isAdmin: false // 管理員標識}復制代碼3.1 初始化用戶信息
// store/reducer.jsconst userInfo = getSessionStore('user') || { // 首先從sessionStorage中獲取數據 username: '', permission: [], isAdmin: false}export const user = (state=userInfo, action) => { switch (action.type) { case 'LOGIN': return pick(keys(state), action.user) default: return state }}復制代碼3.2 實現登錄
首先將store的state和action注入login組件:
import { connect } from 'react-redux'import { doLogin } from 'store/action'import Login from './login'const mapStateToProps = (state, owns) => ({ user: state, ...owns})const mapDispatchToProps = dispatch => ({ dispatchLogin: user => dispatch(doLogin(user))})export default connect( mapStateToProps, mapDispatchToProps)(Login)復制代碼繼而在login.js中實現登錄邏輯:
class Login extends Component { login () { const { dispatchLogin, history } = this.props const { form } = this.state const user = { username: '安歌', permission: ['add'], isAdmin: false } dispatchLogin(user) // 更新store存儲的用戶數據 setSessionStore('user', user) // 將用戶數據存儲在sessionStorage // login success history.push('/front/approval/undo') // 登錄重定向 } }復制代碼四、路由鑒權
上一篇中我們實現了頁面級路由,現在我們需要根據路由配置文件,注冊應用級路由。回顧下我們的路由配置:
export default [ { title: '我的事務', // 頁面標題&一級nav標題 icon: 'icon-home', routes: [{ name: '待審批', path: '/front/approval/undo', component: 'ApprovalUndo' }, { name: '已處理', path: '/front/approval/done', auth: 'add', component: 'ApprovalDone' }] }]復制代碼我們根據path和component信息注冊路由,根據auth信息進行路由鑒權。看下我們如何實現各個路由對應的組件。
在views目錄存放了我們所有的頁面應用組件,index.js則作為組件的入口文件:// views/index.jsimport AsyncComponent from 'components/AsyncComponent'const ApprovalUndo = AsyncComponent(() => import(/* webpackChunkName: "approvalundo" */ 'views/approval/undo'))const ApprovalDone = AsyncComponent(() => import(/* webpackChunkName: "approvaldone" */ 'views/approval/done'))export default { ApprovalUndo, ApprovalDone}復制代碼說明: 關于AsyncComponent的說明已在上篇有所介紹。
4.1 注冊路由
// router/index.js import routesConf from './config'import views from 'views'class CRouter extends Component { render () { return ( { pipe(map(each => { const routes = each.routes return this.generateRoute(routes, each.title) }), flatten)(routesConf) } } /> ) } generateRoute (routes=[], ) { // 遞歸注冊路由 return map(each => each.component ? ( { const reg = /?S*g/ const queryParams = window.location.hash.match(reg) // 匹配路由參數 const { params } = props.match Object.keys(params).forEach(key => { // 去除?參數 params[key] = params[key] && params[key].replace(reg, '') }) props.match.params = { ...params } const merge = { ...props, query: queryParams ? queryString.parse(queryParams[0]) : {} } const View = views[each.component] const wrapperView = ( // 包裝組件設置標簽頁標題 ) return wrapperView } } /> ) : this.generateRoute(each.routes, title), routes) }}const mapStateToProps = (state, owns) => ({ user: prop('user', state), ...owns})export default connect( mapStateToProps)(CRouter)復制代碼我們的路由配置文件支持多級嵌套,遞歸注返回的Route路由也是嵌套的數組,最后需要借助flatten將整個路由數組打平。
4.2 權限管理
權限管理分為登錄校驗和權限校驗,默認我們的應用路由都是需要登錄校驗的。
class CRouter extends Component { generateRoute (routes=[], ) { // ... // 在上一個版本中直接將wrapperView返回,這個版本包裹了一層登錄校驗 return this.requireLogin(wrapperView, each.auth) } requireLogin (component, permission) { const { user } = this.props const isLogin = user.username || false // 登錄標識, 從redux取 if(!isLogin) { // 判斷是否登錄 return } // 如果當前路由存在權限要求,則再進入全權限校驗 return permission ? this.requirePermission(component, permission) : component } requirePermission (component, permission) { const permissions = path(['user', 'permission'], this.props) // 用戶權限, 從redux取 if(!permissions || !this.checkPermission(permission, permissions)) return return component } checkPermission (requirePers, userPers) { const isAdmin = path(['user', 'isAdmin'], this.props) // // 超管標識, 從redux取 if(isAdmin) return true if(typeof userPers === 'undefined') return false if(Array.isArray(requirePers)) { // 路由權限為數組 return requirePers.every(each => userPers.includes(each)) } else if(requirePers instanceof RegExp) { // 路由權限設置為正則 return userPers.some(each => requirePers.test(each)) } return userPers.includes(requirePers) // 路由權限設置為字符串 }}復制代碼在checkPermission函數中實現了字符串、數組和正則類型的校驗,因此,在我們路由配置文件中的auth可以支持字符串、數組和正則三種方式去設置。
如上,結合redux的應用,我們輕松實現可配置、高可復用的路由鑒權功能。系統會根據當前用戶的權限列表(一般通過接口由后端返回)與配置文件中定義的權限要求進行校驗,如果無權限,則重定向至Permission Error頁面。
總結
以上是生活随笔為你收集整理的dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求组合数python_给定一个序列求指定
- 下一篇: 1ke android逆向助手_andr