【React系列】高阶组件

本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MDAzNzkwNA==&action=getalbum&album_id=1566025152667107329)

一. 高阶组件

1.1. 认识高阶组件

什么是高阶组件呢?相信很多同学都听说过,也用过 高阶函数,它们非常相似,所以我们可以先来回顾一下什么是 高阶函数。

高阶函数的维基百科定义:至少满足以下条件之一:

  • 接受一个或多个函数作为输入;
  • 输出一个函数;

JavaScript中比较常见的filter、map、reduce都是高阶函数。

那么什么是高阶组件呢?

  • 高阶组件的英文是 Higher-Order Components,简称为 HOC
  • 官方的定义:高阶组件是参数为组件,返回值为新组件的函数

我们可以进行如下的解析:

  • 首先, 高阶组件 本身不是一个组件,而是一个函数
  • 其次,这个函数的参数是一个组件返回值也是一个组件

高阶组件的调用过程类似于这样:

const EnhancedComponent = higherOrderComponent(WrappedComponent);

高阶函数的编写过程类似于这样:

function higherOrderComponent(WrapperComponent) {return class NewComponent extends PureComponent {render() {return <WrapperComponent/>}}
}

组件的名称问题:

  • 在ES6中,类表达式中类名是可以省略的,所以可以可以写成下面的写法:
function higherOrderComponent(WrapperComponent) {return class extends PureComponent {render() {return <WrapperComponent/>}}
}
  • 另外,组件的名称都可以通过displayName来修改:
    在这里插入图片描述
    完整的代码,我们可以这样来编写:
import React, { PureComponent } from 'react';function higherOrderComponent(WrapperComponent) {return class NewComponent extends PureComponent {render() {return <WrapperComponent/>}}
}class App extends PureComponent {render() {return (<div>App</div>)}
}export default higherOrderComponent(App);

高阶组件并不是React API的一部分,它是基于React的组合特性而形成的设计模式

高阶组件在一些React第三方库中非常常见:

  • 比如redux中的connect;
  • 比如react-router中的withRouter

在我们的开发中,高阶组件可以帮助我们做哪些事情呢?

1.2. 高阶组件的使用

1.2.1. props的增强

不修改原有代码的情况下,添加新的props

假如我们有如下案例:

class Header extends PureComponent {render() {const { name, age } = this.props;return <h2>Header {name + age}</h2>}
}export default class App extends PureComponent {render() {return (<div><Header name="aaa" age={18} /></div>)}
}

我们可以通过一个高阶组件,让使用者在不破坏原有结构的情况下对某个组件增强props

function enhanceProps(WrapperCpn, otherProps) {return props => <WrapperCpn {...props} {...otherProps} />
}const EnhanceHeader = enhanceProps(Header, {height: 1.88})
  • 有点拦截器和java动态代理的意思

利用高阶组件来共享 Context 属性

import React, { PureComponent, createContext } from 'react';const UserContext = createContext({nickname: "默认",level: -1
})function Header(props) {return (<UserContext.Consumer>{value => {const { nickname, level } = value;return <h2>Header {"昵称:" + nickname + "等级" + level}</h2>}}</UserContext.Consumer>)
}function Footer(props) {return (<UserContext.Consumer>{value => {const { nickname, level } = value;return <h2>Footer {"昵称:" + nickname + "等级" + level}</h2>}}</UserContext.Consumer>)
}const EnhanceHeader = enhanceProps(Header, { height: 1.88 })export default class App extends PureComponent {render() {return (<div><UserContext.Provider value={{ nickname: "why", level: 90 }}><Header /><Footer /></UserContext.Provider></div>)}
}

利用高阶组件withUser

import React, { PureComponent, createContext } from 'react';const UserContext = createContext({nickname: "默认",level: -1
})function withUser(WrapperCpn) {return props => {return (<UserContext.Consumer>{value => {return <WrapperCpn {...props} {...value}/>}}</UserContext.Consumer>)}
}function Header(props) {const { nickname, level } = props;return <h2>Header {"昵称:" + nickname + "等级:" + level}</h2>
}function Footer(props) {const { nickname, level } = props;return <h2>Footer {"昵称:" + nickname + "等级:" + level}</h2>
}const UserHeader = withUser(Header);
const UserFooter = withUser(Footer);export default class App extends PureComponent {render() {return (<div><UserContext.Provider value={{ nickname: "why", level: 90 }}><UserHeader /><UserFooter /></UserContext.Provider></div>)}
}

1.2.2. 利用高阶组件进行鉴权判断

在开发中,我们可能遇到这样的场景:

  • 某些页面是必须用户登录成功才能进行进入;
  • 如果用户没有登录成功,那么直接跳转到登录页面;

这个时候,我们就可以使用高阶组件来完成鉴权操作:

function LoginPage() {return <h2>LoginPage</h2>
}function CartPage() {return <h2>CartPage</h2>
}export default class App extends PureComponent {render() {return (<div><CartPage/></div>)}
}

编写鉴权的高阶组件:

function loginAuth(Page) {return props => {if (props.isLogin) {return <Page/>} else {return <LoginPage/>}}
}

完整的代码如下:

import React, { PureComponent } from 'react';function loginAuth(Page) {return props => {if (props.isLogin) {return <Page/>} else {return <LoginPage/>}}
}function LoginPage() {return <h2>LoginPage</h2>
}function CartPage() {return <h2>CartPage</h2>
}const AuthCartPage = loginAuth(CartPage);export default class App extends PureComponent {render() {return (<div><AuthCartPage isLogin={true}/></div>)}
}

1.2.3. 生命周期劫持

import React, { PureComponent } from 'react';class Home extends PureComponent {UNSAFE_componentWillMount() {this.begin = Date.now();}componentDidMount() {this.end = Date.now();const interval = this.end - this.begin;console.log(`Home渲染使用时间:${interval}`)}render() {return (<div><h2>Home</h2><p>我是home的元素,哈哈哈</p></div>)}
}class Detail extends PureComponent {UNSAFE_componentWillMount() {this.begin = Date.now();}componentDidMount() {this.end = Date.now();const interval = this.end - this.begin;console.log(`Detail渲染使用时间:${interval}`)}render() {return (<div><h2>Detail</h2><p>我是detail的元素,哈哈哈</p></div>)}
}export default class App extends PureComponent {render() {return (<div><Home/><Detail/></div>)}
}

我们可以定义如下高阶组件:

function logRenderTime(WrapperCpn) {return class extends PureComponent {UNSAFE_componentWillMount() {this.begin = Date.now();}componentDidMount() {this.end = Date.now();const interval = this.end - this.begin;console.log(`Home渲染使用时间:${interval}`)}render() {return <WrapperCpn {...this.props}/>}}
}const LogHome = logRenderTime(Home);
const LogDetail = logRenderTime(Detail);

完整代码如下:

import React, { PureComponent } from 'react';function logRenderTime(WrapperCpn) {return class extends PureComponent {UNSAFE_componentWillMount() {this.begin = Date.now();}componentDidMount() {this.end = Date.now();const interval = this.end - this.begin;console.log(`${WrapperCpn.name}渲染使用时间:${interval}`)}render() {return <WrapperCpn {...this.props}/>}}
}class Home extends PureComponent {render() {return (<div><h2>Home</h2><p>我是home的元素,哈哈哈</p></div>)}
}class Detail extends PureComponent {render() {return (<div><h2>Detail</h2><p>我是detail的元素,哈哈哈</p></div>)}
}const LogHome = logRenderTime(Home);
const LogDetail = logRenderTime(Detail);export default class App extends PureComponent {render() {return (<div><LogHome /><LogDetail /></div>)}
}

这个写法其实就是提取公共代码进行复用而已。

1.3. 高阶函数的意义

我们会发现利用高阶组件可以针对某些React代码进行更加优雅的处理。

其实早期的React有提供组件之间的一种复用方式是mixin,目前已经不再建议使用:

  • Mixin 可能会相互依赖,相互耦合,不利于代码维护
  • 不同的Mixin中的方法可能会相互冲突
  • Mixin非常多时,组件是可以感知到的,甚至还要为其做相关处理,这样会给代码造成滚雪球式的复杂性

当然,HOC也有自己的一些缺陷:

  • HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难;
  • HOC可以劫持props,在不遵守约定的情况下也可能造成冲突;

Hooks的出现,是开创性的,它解决了很多React之前的存在的问题,比如this指向问题、比如HOC的嵌套复杂度问题等等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/233488.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql高可用方案之MHA

mysql集群高可用方案&#xff1a; 单主&#xff1a;keepalived、MHA、MMM 多主&#xff1a;MySQL cluster 、PXC MHA的工作原理 MHA node 运行在每台MySQL服务器上&#xff0c;MHA Manager会定时探测集群中的master节点&#xff0c;当master出现故障时&#xff0c;它可以自…

Java方法用法及解析

在 Java 中&#xff0c;方法&#xff08;Method&#xff09;是用于执行特定任务的代码块。它是一个函数&#xff0c;用于封装一段可重复执行的代码&#xff0c;并可以被其他代码调用。方法定义了一系列操作的步骤&#xff0c;并提供了一种结构化和可复用的方式来组织和执行这些…

[VUE]4-状态管理vuex

目录 状态管理 vuex 1、vuex 介绍 2、安装 3、使用方式 4、总结 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数据结构和算法&#xff0c;初步涉猎Python人工智…

【源码预备】Calcite基础知识与概念:关系代数概念、查询优化、sql关键字执行顺序以及calcite基础概念

文章目录 一. 关系代数的基本知识二. 查询优化三. SQL语句的解析顺序1. FROM2. WHERE3. GROUP BY4. HAVING5. SELECT 四. Apache Calcite中的基本概念1. Adapter2. Calcite中的关系表达式2.1. 关系表达式例子2.2. 源码底层结构 3. Calcite的优化规则4. Calcite的Trait--算子物理…

02 Deep learning algorithm

Neural Networks target&#xff1a; inference&#xff08;prediction&#xff09;training my own modelpractical advice for building machine learning systemdecision Tress application: speech&#xff08;语音识别&#xff09; ----> images(计算机视觉)—> t…

数据结构-测试4

一、判断题 1.队列结构的顺序存储会产生假溢出现象。 &#xff08;T&#xff09; 2.度为二的树就是二叉树。(F) 二叉树的度可以小于等于2 3. 栈是插入和删除只能在一端进行的线性表&#xff1b;队列是插入在一端进行&#xff0c;删除在另一端进行的线性表。&#xff08;T&…

【CMake】1. VSCode 开发环境安装与运行

CMake 示例工程代码 https://github.com/LABELNET/cmake-simple 插件 使用 VSCode 开发C项目&#xff0c;安装 CMake 插件 CMakeCMake ToolsCMake Language Support &#xff08;建议&#xff0c;语法提示) 1. 配置 CMake Language Support , Windows 配置 donet 环境 这…

异地环控设备如何远程维护?贝锐蒲公英解决远程互联难题

青岛某企业致力于孵化设备、养禽设备和养猪设备的研发、生产和服务&#xff0c;历经三十多年发展&#xff0c;目前已成长为行业主要的养殖装备及工程服务提供商&#xff0c;产品覆盖养殖产业链中绝大多数环节&#xff0c;涉及自动化设备、环控设备、整体解决方案等。 在实际应用…

Python3从零基础到入门(1)

目录 一、环境搭建 1.检测Python环境 2.下载安装Python环境 3.VSCode中配置Python环境 二、第一个程序 1.编码 2.输出 3.标识符 4.import 5.保留字 6.注释 7.缩进 三、变量和赋值 1.Python 中的变量 2.变量的赋值 3.多个变量赋值 四、基础数据类型 1.类型查看…

以unity技术开发视角对android权限的讲解

目录 前言 Android权限分类 普通权限 普通权限定义 普通权限有哪些 危险权限 危险权限的定义 危险权限有哪些 动态申请权限实例 申请单个权限实例 第一步&#xff1a;在清单文件中声明权限 第二步&#xff1a;在代码中进行动态申请权限 申请多个权限实例 第一步&am…

以对象为中心的视频编辑;SDXL高质量缩小版;Transformer在FPGA上实现12.8倍速度提升;深入研究ViT固有问题

本文首发于公众号&#xff1a;机器感知 以对象为中心的视频编辑&#xff1b;SDXL高质量缩小版&#xff1b;Transformer在FPGA上实现12.8倍速度提升&#xff1b;深入研究ViT固有问题 VASE: Object-Centric Appearance and Shape Manipulation of Real Videos 现有方法通过文生…

前端学习笔记 3:Vue 工程

前端学习笔记 3&#xff1a;Vue 工程 上一篇文章介绍了如何在单一 Html 页面中使用 Vue&#xff0c;本文介绍如何从头开始用 Vue 构建一个前端工程项目。 1.环境准备 Vue 框架代码的创建依赖于 Node.js&#xff0c;因此需要先安装 Node.js。 2.创建和启动 2.1.创建 通过以…

MongoDB高级集群架构设计

两地三中心集群架构设计 容灾级别 RPO & RTO RPO&#xff08;Recovery Point Objective&#xff09;&#xff1a;即数据恢复点目标&#xff0c;主要指的是业务系统所能容忍的数据丢失量。RTO&#xff08;Recovery Time Objective&#xff09;&#xff1a;即恢复时间目标&…

OpenHarmony内存泄漏指南 - 解决问题(综合)

本系列文章旨在提供定位与解决OpenHarmony应用与子系统内存泄露的常见手段与思路&#xff0c;将会分成几个部分来讲解。首先我们需要掌握发现内存泄漏问题的工具与方法&#xff0c;以及判断是否可能存在泄漏。接着需要掌握定位泄漏问题的工具&#xff0c;以及抓取trace、分析tr…

智能计价器Scratch-第14届蓝桥杯Scratch省赛真题第5题

5. 智能计价器&#xff08;80分&#xff09; 背景信息&#xff1a;A城市的出租车计价&#xff1a;3公里以内13元&#xff0c;基本单价每公里2.3元(超过3公里的部分&#xff0c;不满1公里按照1公里收费&#xff09;&#xff0c;燃油附加费每运次1元。例如&#xff1a;3.2公里的…

自动化测试报告生成(Allure)

之前尝试使用过testNG自带的测试报告、优化过reportNG的测试报告&#xff0c;对这两个报告都不能满意。后经查找资料&#xff0c;发现有个神器&#xff1a; Allure&#xff08;已经有allure2了&#xff0c;笔者使用的就是allure2&#xff09;&#xff0c;生成的测试报告与上述…

【回溯算法】n-皇后

导航 题目来源题目描述示例思路完整代码 题目来源 n-皇后 题目描述 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一…

【Linux Shell】9. 流程控制

文章目录 【 1. if else 判断 】1.1 if1.2 if else1.3 if elif else1.4 实例 【 2. case 匹配 】【 3. 循环 】3.1 for 循环3.2 while 循环3.3 until 循环3.4 无限循环3.5 跳出循环3.5.1 break 跳出所有循环3.5.2 continue 仅跳出当前循环 【 1. if else 判断 】 1.1 if fi 是…

【算法】递归算法理解(持续更新)

这里写目录标题 一、递归算法1、什么情况下可以使用递归&#xff1f;2、递归算法组成部分3、案例&#xff1a;求n的阶乘4、编写一个递归函数来计算列表包含的元素数。5、通过递归找到列表中最大的数字。6、通过递归的方式实现二分查找算法。 一、递归算法 递归&#xff08;Rec…

“单项突出”的赢双科技IPO加速,比亚迪是最强助力?

近日&#xff0c;新能源汽车核心部件供应商赢双科技首次递表科创板&#xff0c;其凭借旋转变压器产品就坐稳了新能源车企主要供应商的地位&#xff0c;从核心业务及业绩情况来看&#xff0c;赢双科技不愧为“单项冠军”。 据悉&#xff0c;赢双科技本次IPO拟募资8.47亿元&…