博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于React的高阶组件
阅读量:6316 次
发布时间:2019-06-22

本文共 2854 字,大约阅读时间需要 9 分钟。

什么是高阶组件?

高阶组件是什么?乍一听,感觉是个很高级的概念,但是不要被这个名词吓到,说简单点 就是给已有的一个组件外面“包一层”。 我们知道 “高阶函数” 是传入函数作为参数, 高阶组件 其实就是传入 组件作为参数,并返回一个新组件。

高阶组件的作用

高阶组件的作用是什么?项目开发当中,通常我们会把一些公用的逻辑抽离出来, 并且应用到很多组件上,给组件赋予一个新的能力,这时候就需要用到它。

常见的应用场景

  • 路由权限控制, 同一个路由地址,根据不同的用户角色或者登陆状态, 展示不同的UI视图
  • 当你想要给很多组件赋予新的props

简而言之,如果你需要给很多组件都写相同的判断逻辑,那么可以考虑提取出一个高阶组件

实际场景: 路由权限控制

记得以前开发vue 项目的时候也遇到过类似的问题,那时用的vue-router,实现方式是在全局的router.beforeEach方法中获取用户信息,根据用户的角色和权限跳转到不同的页面。参考

一个实现路由权限控制的高阶组件:

const LodingUserTip = () => {  return (    

正在获取用户信息,稍后...

)}const UnAuthoriedTip = () => { return (

抱歉,您没有访问该页面的权限...

)}const authDecorator = WrappedComponent => {// auth 组件是最终返回的高阶组件 const Auth = props => { const { match: {path, params}, currentUser: {role_type: roleType}, userLoading, history, location, } = props const {match} = props // 用户信息正在加载 if (userLoading) { return
} // 当前登录用户没有访问权限 if (!roles.includes(roleType)) { return
} // 如果没有找到对应页面,则跳转至该权限对应的默认页面 const {allowedUrl, defaultUrl} = AUTH_MAP[roleType] if (!allowedUrl.includes(path)) { history.push(defaultUrl) return null } // 还可以把额外的 props传递给你使用的组件 return (
) } const mapStateToProps = ({ users, loading: {models: {users: userLoading}}, }) => { return { currentUser: users.currentUser, userLoading, } } return withRouter(connect(mapStateToProps)(Auth))}export default authDecorator复制代码

上面这段代码便是一个高阶组件, 通常我们会请求后端接口返回给我们一个当前用户的roleType, 我们在前端会存一个map,根据不同的roleType映射到的不同的路由, map结构如下:

export const AUTH_MAP = {  admin: {    allowedUrl: [      '/a/b',    ],    defaultUrl: '/f',  },  superAdmin: {    allowedUrl: [      '/a/b',      '/c/d',    ],    defaultUrl: '/e',    }}复制代码

使用的时候可以配合装饰器,更简单方便:

@authDecoratorclass PageOneComponent extends React.Component {...复制代码

高阶组件中会判断 当前的用户角色与当前的路由是否匹配,若匹配不成功则显示默认信息,或者跳转到默认url(或者登陆页)

遇到的问题

在使用antd的Form.create(onFieldsChange:(props, fields) => {}) 我很疑惑这里 为什么能获取到组件的props, 最后明白: 其实Form.create()返回了一个高阶组件,会接收到所有传给组件的props, 当fields变化的时候,antd执行onFieldsChange并把props传进去便可以。

但有一个要注意,如果一个组件有多个装饰器(需要被多个高阶组件包裹),需要注意顺序,比如下面这个图片,我希望在onFieldsChange 中获取 从 redux 拿到的 dictionary信息,这样是获取不到的,因为 最先执行的connect, 然后才执行的 Form.create()方法,Form.create()返回的高阶组件只能获取到之后传递给组件的props.

如图,debugger打断点 看到 props中 没有 dictionary

要想拿到所有的props,请按照下图这样做:(最先执行的是Form.create()返回的函数,所以后面执行的函数以及传递的props都会被onFieldsChange接收到):

需要注意的点

  • ref 无法传递的问题: 由于你使用的组件其实被包裹了一层, 所以上层组件获取的ref, 实际上是获取的高阶组件。 具体详情请看我的另外一篇博客
  • 被包裹的组件自身的静态方法默认是不会出现在高阶组件中的,要想解决这个问题,我们可以 MyHOC.staticMethod = WrappedComponent.staticMethod 这样明确的将静态方法传递给高阶组件,但是这样太不严谨了,很容易漏掉。官方推荐的最佳实践是使用 第三方库 自动copy 静态方法
  • 高阶组件(HOC)应该是无副作用的纯函数,且不应该修改原组件
  • 给高阶组件函数传参除了传入 一个组件 还想传入 其他参数怎么办? 我觉得可以写成 类似 connect的柯里化的形式比较好。 本文中使用到的高阶组件基本都是单参数,如果想传递多个参数也是没问题的,可以看官网的, 例子中selectData 便是第二个参数,作为获取数据的回调,获取数据的逻辑便可以从高阶组件中解耦。

参考链接

转载地址:http://oyyaa.baihongyu.com/

你可能感兴趣的文章
注册和上传文件(头像)
查看>>
使用OVS
查看>>
键盘回收的几种方法
查看>>
Python(条件判断和循环)
查看>>
day4 linux安装python
查看>>
LeetCode Container With Most Water (Two Pointers)
查看>>
vue (v-if show 问题)
查看>>
https基础
查看>>
css3 canvas之刮刮卡效果
查看>>
并查集模板
查看>>
RESTful Mongodb
查看>>
BZOJ3237:[AHOI2013]连通图(线段树分治,并查集)
查看>>
如何提高Ajax性能
查看>>
Android--自定义加载框
查看>>
LINUX下 lamp安装及配置
查看>>
BZOJ3105 [cqoi2013]新Nim游戏
查看>>
困惑的前置操作与后置操作
查看>>
SDNU 1269.整数序列(水题)
查看>>
BZOJ 2118 Dijkstra
查看>>
Go语言基础之结构体
查看>>