dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)
【React系列】手把手帶你擼后臺系統(tǒng)(Redux與路由鑒權(quán))
來源:https://juejin.im/post/5d9b5ddee51d45781b63b8f7
上一篇我們介紹了系統(tǒng)架構(gòu),這一篇將繼續(xù)介紹:
- Redux的應用
- 登錄授權(quán)
- 路由鑒權(quán)
二、Redux應用
側(cè)邊導航欄(Sidebar)我們實現(xiàn)了根據(jù)配置渲染菜單項,現(xiàn)在我們要繼續(xù)完善它的功能:導航高亮與鑒權(quán)。我們通過redux管理我們Sidebar的狀態(tài),想要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數(shù)據(jù) ...owns})const mapDispatchToProps = dispatch => ({ dispatchSideBar: sidebar => dispatch(updateSidebarState(sidebar)) // 更新數(shù)據(jù)狀態(tài)})export default connect( mapStateToProps, mapDispatchToProps)(SideBar)復制代碼2.1 初始化Sidebar數(shù)據(jù)
初始化Sidebar數(shù)據(jù)主要做兩點:
- 默認的路由配置數(shù)據(jù)里面沒有標識高亮狀態(tài),初始化過程增加active標志位;
- 為父級導航項增加key值標志位,用于檢測收合狀態(tài);
經(jīng)處理后的路由配置數(shù)據(jù)新增了active和key兩個屬性:
2.2 檢測高亮渲染側(cè)邊導航欄過程需要檢測高亮狀態(tài):根據(jù)當前路由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) // 返回檢測后的路由數(shù)據(jù) } } // 省略代碼... 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組件需要經(jīng)由withRouter包裹后才能在組件內(nèi)獲取路由相關信息。
三、登錄授權(quán)
這里設定的場景是:用戶的登錄數(shù)據(jù)在當前會話期內(nèi)有效(sessionStorage存儲用戶信息),用戶信息全局可用(redux管理)。假定我們存儲的用戶數(shù)據(jù)有:
{ username: '', // 帳號 permission: [], // 用戶權(quán)限列表 isAdmin: false // 管理員標識}復制代碼3.1 初始化用戶信息
// store/reducer.jsconst userInfo = getSessionStore('user') || { // 首先從sessionStorage中獲取數(shù)據(jù) 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 實現(xiàn)登錄
首先將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中實現(xiàn)登錄邏輯:
class Login extends Component { login () { const { dispatchLogin, history } = this.props const { form } = this.state const user = { username: '安歌', permission: ['add'], isAdmin: false } dispatchLogin(user) // 更新store存儲的用戶數(shù)據(jù) setSessionStore('user', user) // 將用戶數(shù)據(jù)存儲在sessionStorage // login success history.push('/front/approval/undo') // 登錄重定向 } }復制代碼四、路由鑒權(quán)
上一篇中我們實現(xiàn)了頁面級路由,現(xiàn)在我們需要根據(jù)路由配置文件,注冊應用級路由。回顧下我們的路由配置:
export default [ { title: '我的事務', // 頁面標題&一級nav標題 icon: 'icon-home', routes: [{ name: '待審批', path: '/front/approval/undo', component: 'ApprovalUndo' }, { name: '已處理', path: '/front/approval/done', auth: 'add', component: 'ApprovalDone' }] }]復制代碼我們根據(jù)path和component信息注冊路由,根據(jù)auth信息進行路由鑒權(quán)。看下我們?nèi)绾螌崿F(xiàn)各個路由對應的組件。
在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) // 匹配路由參數(shù) const { params } = props.match Object.keys(params).forEach(key => { // 去除?參數(shù) 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路由也是嵌套的數(shù)組,最后需要借助flatten將整個路由數(shù)組打平。
4.2 權(quán)限管理
權(quán)限管理分為登錄校驗和權(quán)限校驗,默認我們的應用路由都是需要登錄校驗的。
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 } // 如果當前路由存在權(quán)限要求,則再進入全權(quán)限校驗 return permission ? this.requirePermission(component, permission) : component } requirePermission (component, permission) { const permissions = path(['user', 'permission'], this.props) // 用戶權(quán)限, 從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)) { // 路由權(quán)限為數(shù)組 return requirePers.every(each => userPers.includes(each)) } else if(requirePers instanceof RegExp) { // 路由權(quán)限設置為正則 return userPers.some(each => requirePers.test(each)) } return userPers.includes(requirePers) // 路由權(quán)限設置為字符串 }}復制代碼在checkPermission函數(shù)中實現(xiàn)了字符串、數(shù)組和正則類型的校驗,因此,在我們路由配置文件中的auth可以支持字符串、數(shù)組和正則三種方式去設置。
如上,結(jié)合redux的應用,我們輕松實現(xiàn)可配置、高可復用的路由鑒權(quán)功能。系統(tǒng)會根據(jù)當前用戶的權(quán)限列表(一般通過接口由后端返回)與配置文件中定義的權(quán)限要求進行校驗,如果無權(quán)限,則重定向至Permission Error頁面。
總結(jié)
以上是生活随笔為你收集整理的dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求组合数python_给定一个序列求指定
- 下一篇: fuse java_java中的Fuse