权限控制算是软件项目中的常用功能了。在前端项目开发过程中,权限控制一般分为两个维度:页面级别和页面元素级别。
今天我们来聊一下在React项目中如何实现页面元素级别的鉴权功能。
前面有两篇文章分别介绍了React的高阶组件的使用方法和React的Render Prop的使用方法,即各自优缺点。
接下来我们用React的高阶组件方式和React的Render Prop方式分别实现一下React组件的鉴权功能。
在React项目中,不同的用户权限所能看到的组件是不同的,例如管理者与普通用户,登录同一个网站,看到的内容是不同的。
假设我们项目某个页面中有两个组件List组件和Header组件,这两个组件需要根据用户的权限显示不同的内容,该如何实现呢,代码如下:
import React,{Component} from 'react';
// 模拟获取用户权限
function getAuthor(){
return new Promise((resolve,rekect)=>{
setTimeout(()=>{
let index = Math.round(1-Math.random());
let author = ['admin','user'][index]
resolve(author)
},1000)
})
}
class List extends Component{
state = {author:''}
async componentDidMount(){
// 在生命周期中获取用户权限;
let author = await getAuthor();
this.setState({author})
}
render(){
// 在render中根据用户权限显示不同的内容
const {author} = this.state
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
}
class Header extends Component{
state = {author:''}
async componentDidMount(){
// 在生命周期中获取用户权限;
let author = await getAuthor();
this.setState({author})
}
render(){
// 在render中根据用户权限显示不同的内容
const {author} = this.state
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
}
function App() {
return (
<div className="App">
<List />
<Header/>
</div>
);
}
export default App;
阅读源码,我们在List组件和Header组件中都进行了获取用户权限的操作,如果项目中需要鉴权的组件比较多,那么所有需要鉴权的组件都需要去添加这部分代码,实在是冗余,其实这部分代码是可以被提取出来的。
首先我们使用React的高阶组件的方式来优化代码,在此之前我们要清楚什么是高阶组件,高阶组件本身是一个函数,其内部封装了一些通用逻辑,其参数为组件,其调用结果返回一个新的组件,清楚高阶组件的这些特性之后就能轻松写出高阶组件了,代码如下:
import React,{Component} from 'react';
//模拟获取用户权限
function getAuthor(){
return new Promise((resolve,rekect)=>{
setTimeout(()=>{
let index = Math.round(1-Math.random());
let author = ['admin','user'][index]
resolve(author)
},1000)
})
}
// 需要鉴权的组件,将权限提取为参数
function List(author){
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
// 需要鉴权的组件,将权限提取为参数
function Header(author){
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
// 1、定义高阶组件本事是一个函数
// 2、参数是一个组件
function AuthorHoc(Com){
// 3、返回结果是一个组件
return class extends Component{
constructor(props){
super(props)
}
// 4、内部封装通用逻辑,获取用户权限
state={author:''}
async componentDidMount(){
let author = await getAuthor();
this.setState({author})
}
render(){
return <div>
<h1>wrap</h1>
{/* 5、调用传递的组件,
并将高阶组件获取的权限
传递到目标组件*/}
<Com author={this.state.author} {...prop}/>
</div>
}
}
}
let Newlist = AuthorHoc(List);
let NewHeader = AuthorHoc(Header);
function App() {
return (
<div className="App">
<Newlist/>
<NewHeader/>
</div>
);
}
export default App;
仔细阅读代码,代码中主要进行了如下几部操作:
第一步,我们将组件中的通用逻辑提取到了高阶组件中,通用逻辑指的是获取用户权限这部分代码。
第二步,调用高阶组件这个函数,并且将需要被鉴权的组件作为参数,调用结果得到了新的组件,NewList组件与NewHeader组件。这两个新组件可以直接使用,其内部进行了鉴权,这便是高阶组件的使用方式。
接下来我们用React的 render prop方式来优化代码。先来看下官方解释:
“render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术。 具有 render prop 的组件接受一个函数,该函数返回一个 React 元素并调用它而不是实现自己的渲染逻辑。 https://react.docschina.org/docs/render-props.html
用大白话来讲,就是将组件中的通用逻辑提取到一个公共组件中,这个公共组件渲染的内容由其参数render决定,render这个参数是一个函数,这个函数调用会返回React组件,从而实现定制化渲染。看代码:
import React,{Component} from 'react';
function getAuthor(){
return new Promise((resolve,rekect)=>{
setTimeout(()=>{
let index = Math.round(1-Math.random());
let author = ['admin','user'][index]
resolve(author)
},1000)
})
}
function List(author){
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
function Header(author){
if(author==='admin'){
return <div>管理员</div>
}else{
return <div>普通户</div>
}
}
class AuthorProp extends Component{
constructor(props){
super(props)
}
// 抽离公共逻辑
state = {author:''}
async componentDidMount(){
let author = await getAuthor();
this.setState({author})
}
render(){
return <div>
<h1>prop</h1>
{/* 调用render,render的返回值是一个组件,
这个组件决定渲染内容
*/}
{this.props.render(this.state.author)}
</div>
}
}
function App() {
return (
<div className="App">
{/* render本质是个函数,
其返回值是一个React组件 */}
<AuthorProp render={prop=>List(prop)} />
</div>
);
}
export default App;
阅读代码,我们将通用逻辑封装到了一个公共组件中,这个公共组件在调用时必须传递一个render参数(也可以换成其他单词),render参数的本质是一个函数,这个函数在公共组件内部调用返回一个React组件,返回的React组件决定渲染什么内容。
在我们的案例中,render函数返回的组件要依赖公共组件获取的用户权限author,所以我们通过render函数将author传递给了需要被鉴权的组件。
这里的render像是一个特殊的盒子,盒子里面装的是需要被渲染的组件,这个盒子会在公共组件内部被打开,打开时可以传递参数author,author会传递到组件中,组件根据author渲染不同的内容。
仔细对比两种方式,使用render prop相较于高阶组件,项目中并未新增组件,也不存在组件嵌套过深的问题,个人感觉比较灵活。
以上便是使用React的高阶组件方式和React的Render Prop方式分别实现一下React组件的鉴权功能,如果你有什么建议或者想法欢迎留言。
下篇文章用React的自定义hook函数来实现组件的鉴权功能。