react高阶组件和hooks

react高阶组件和hooks1 react 高阶组件 2 hooks 语法 3 路由 6 0 自封装 withRouter 函数

1. react高阶组件

1.1 高阶组件的概念

高阶组件(Higher Order Component,简称:HOC ): 是 React 中用于重用组件逻辑的高级技术, 它本身不是react中的组件, 而是一个函数, 这个函数接受一个react组件作为参数,并返回一个新组件, 实现了对原有组件的增强和优化, 可以对原有组件中的state, props和逻辑执行增删改操作, 一般用于代码重用和组件增强优化

概述:高阶组件是一个函数,而不是组件,但其参数和返回值都是组件

1.2 高阶组件的使用场景

1.2.1 需要代码重用时

react如果有多个组件都用到同一端逻辑,这是就可以把共同的逻辑部分提取出来,利用高阶组件的形式将这段逻辑整合到每一个组件中,从而减少代码的逻辑重复。

1.2.2 需要组件增强优化时

比如我们在项目中使用的组件有些不是自己写的,而是从网上撸下来的,但是第三方写的组件可能比较复杂,有时不能完全满足需求,且第三方组件不易修改,此时也可以用高阶组件。在不修改原始组件的前提下,对组件添加满足实际开发需求的功能。

一般来说,高阶组件在的父组件,会对原始组件模板做增强优化

return ( 
  
)

1.3 高阶组件的实现方式

1.3.1 属性代理

流程:通过创建新组件来包裹原始组件,把原始组件作为新组件的子组件渲染

功能:可实现对原始组件的 props数据更新组件模板更新

示例代码如下:

import React, { Component } from 'react' function myHoc(OldCom){ return class NewCom extends Component { constructor(props){ super(props); console.log(props); // 路由信息会传入高阶组件的props中,可以对它进行增删改 } render() { return ( // 如果返回一个新模板,相当于把原始组件直接替换了,这就是渲染劫持 return 
  

这是订单页的高阶组件

// 如果要返回原始组件模板,把原始组件作为子组件返回即可 // return ) } } } export default myHoc // 导出高阶组件这个函数

注意:在构造器中路由信息会传入高阶组件的props中,可以对它进行增删改

由于props是只读的,不能修改,要对其进行深复制,然后再进行修改

有两种深复制方式如下:

// this.tempProps = JSON.parse(JSON.stringify(props)) 
  • 第一种深复制会丢失函数,因为JSON里面不识别函数,所以不能放函数
this.tempProps = {...props} 
  • 第二种深复制不会丢失函数,但只能深复制第一层。

此处使用第二种方式,对props进行增删改操作:

this.tempProps.name = "张三" console.log(this.tempProps); 
delete this.tempProps.match // ES5 删除属性 var { location, ...tempObj} = this.tempProps // ES6 解构删除 this.tempProps = tempObj console.log(this.tempProps); 
this.tempProps.history.action = "PUSH" 

在这里只能操作props,不能操作state,无法调用原始组件的state,如果需要修改state数据,请使用 反向继承 实现

在render()渲染函数中,如果需要修改props,需要传入修改后的深复制品

return ( 
  
)

在高阶组件中还可以做登录验证,类似与vue中的路由守卫。

问题:由于路由中配置的是高阶组件,所以路由信息传入到高阶组件中,原始组件中就没有路由信息了,怎么解决?
  • 因为此时原始组件中已经没有路由信息了,即没有登录状态,可通过登录状态做一个if判断。若无登录状态,则返回空,并在100秒后跳转到登录页,若有登录状态,则返回原始组件模板页面。
console.log("orderHoc", this.props); if(this.isLogin){ return 
   }else{ setTimeout(()=>{ this.props.history.push("/login") }, 100) return "" } 
  • 此时需要在render()函数的返回的原始组件中,动态拼接this.props即可传入路由信息
return ( 
  
)

1.3.2 反向继承

流程:通过创建新组件继承自原始组件类,把新组件作为子类,原始组件作为父类

功能:可实现对原始组件的 state状态数据更新组件模板更新

注意:反向继承中,新组件和原始组件要求必须都是类组件

示例代码如下:

import React, { Component } from 'react' function myHoc(OldCom){ return class NewCom extends OldCom{ constructor(props){ super(props); // 因为当前组件类继承于原始组件类,子类可以直接调用父类的数据 console.log("myHoc2", this.state, this.add); // this.setState({ // 此时未能渲染数据 // count: 100 // }) } render(){ return 
  
{super.render()}
} } } export default myHoc

反向继承中,不能返回原始组件标签,因为原始组件是父类,不能作为子组件渲染

return 
   // 错误写法 

需要使用super调用父类的render渲染函数,渲染父类模板

return super.render() 

需要在组件渲染之后更新state数据

componentDidMount = () => { this.setState({ count: 100, age: 20 }, ()=>{ this.add() }) } 
  • this.setState()为异步更新,可在其回调的箭头函数中调用函数
  • 而在构造器中只能调用读取state数据,不能调用setState更新

1.4 高阶组件的渲染劫持

高阶组件的渲染劫持:通过高阶组件把原始组件的模板进行修改和替换

1.4.1 渲染劫持概念

渲染劫持指对一个组件渲染内容的装饰或修改, 一般通过高阶组件来实现, 把一个组件传入高阶组件, 可以对这个组件的模板进行修改后执行渲染, 也可以阻止组件渲染, 并修改组件中的数据和逻辑

1.4.2 渲染劫持的应用

一般用于一些需要登录状态的页面, 在路由请求渲染页面(如订单页)之前, 使用高阶组件判断是否已登录, 如果已登录, 返回订单页模板, 如果没有登录, 返回空, 并跳转到登录页

1.5 高阶组件的实现步骤

1.5.1 新建高阶组件文件 MyHOC.jsx

1.5.2 在文件中创建函数

  • 函数的参数是一个组件OldCom, 函数的返回值也是一个组件 NewCom
function myHoc(OldCom){ return class NewCom extends React.Component{ render(){ let newProps = { age: 10, sex: '男' } return ( 
   ) } } } 

属性代理(上)或者(反向继承)

function myHoc (OldCom){ return class NewCom extends OldCom{ componentDidMount() { this.setState({ name: '李四' }) } render() { return super.render() } } } 

1.5.3 导出高阶组件函数

export default myHoc 

1.5.4 在需要使用高阶组件的原始组件中导入

import MyHOC1 from "./OrderHOC1" // 导入属性代理高阶组件 import MyHOC2 from "./OrderHOC2" // 导入反向继承高阶组件 

1.5.5 在导出组件时,使用高阶组件处理之后,再导出

export default MyHOC1(Order) // 属性代理高阶组件处理 // export default MyHOC2(Order) // 反向继承高阶组件处理 

原始组件示例代码:

// 这是定义原始组件的页面 import React, { Component } from 'react' import MyHOC1 from "./OrderHOC1" import MyHOC2 from "./OrderHOC2" class Order extends Component { state = { count: 0 } add = ()=>{ this.setState({ count: this.state.count + 1 }) } render() { console.log("order", this.state, this.props); return ( 
  

订单页

{this.state.count}

) } } export default MyHOC1(Order) // export default MyHOC2(Order)

2. hooks

hooks语法只适用于函数式组件中,不能用于类组件

2.1 什么是hooks?

hooks是react新版本提供的组合式API语法,类似于vue3组合式API(也叫hooks)

2.2 hooks有什么用?

使函数式组件拥有组件状态和生命周期功能

提供运行效率

避免this指向问题(可以和vue3一样)

2.3 在函数式组件中, 使用hooks语法模拟状态数据的步骤

2.3.1 从react中导入语法函数useState

import React, { useState } from "react" 

2.3.2 在函数式组件中, 使用useState创建状态数据

使用useState创建状态数据,参数是默认值,返回值是 数组

数组中第一个值是状态数据的变量名,第二个值是自定义的更新函数,调用更新函数会刷新视图

有三种类型:

  1. 直接定义单个变量
const [count, setCount] = useState(100) 
  1. 定义多个变量使用对象结构
const [state, setState] = useState({ age: 10, name: "张三", roomList: [] }) 
  1. 定义数组
const [arr, setArr] = useState([1, 2, 3]) 

2.3.3 在组件模板中, 直接调用状态名即可{count}

2.3.4 使用useState函数返回的更新函数,修改状态值setCount(count + 1)

  • 调用更新函数,更新状态,参数是最新值,修改后自动刷新界面
  1. 渲染单数据的写法
 
  1. 渲染对象数据的写法
 
  • 修改对象中的状态数据时可以先修改,再拼接上对应的状态名
  1. 使用useState渲染数组中数据的写法
 
  • 注意:useState定义的引用类型数据,更新时,需要修改数据的内存地址(深拷贝/深复制),才会更新视图

2.4 使用hooks中的useEffect函数实现函数式组件的生命周期

默认第一个参数是回调函数,当组件初始化完成和状态更新时调用,类似于类组件中的render()渲染函数。

第二个参数可以控制回调的调用时机,是一个数组,可选,数组中是状态名,指定那些状态值更新会触发回调函数

有三种实现方法:

  1. 监听所有的数据更新
  • 如果不加第二个参数,初始化时调用,任何状态更新都会调用
useEffect(()=>{ console.log("组件初始化,或有状态更新ComponentWillUpdate") }) 
  1. 只在初始化时监听调用
  • 如果第二个参数是空数组,则只在初始化时调用,状态更新时不会调用
useEffect(()=>{ console.log("组件初始化") }, []) 
  • []表示只在初始化时调用,相当于生命周期componentDidMount

可以在这里请求数据,如请求斗鱼数据:

axios.get("/api/RoomApi/live", { page: 1 }).then(res=>{ console.log(res.data.data); setState({ age: 25, name: "计科", roomList: res.data.data }) }) 

注意:请求数据需要写在useEffect函数的回调中,而[]只在初始化时调用,所以不能写在[]中

  1. 只监听某些数据的更新
  • 如果第二个参数数组中有状态名, 则只会在数组中的状态更新时调用
 useEffect(()=>{ console.log("组件初始化或count或arr更新") }, [count, arr]) 

useEffect()函数的第二个参数是数组时,若里边写状态数据名,则是指定哪些数据更新时可执行回调

3.在react路由6.0中封装withRouter高阶组件

react-router6.0版本废弃了组件内的props路由信息( history, location, match ),6.0之后的版本,组件内默认都没有路由信息,包括withRouter高阶组件也被废弃了,需要使用hooks组合式API导入路由信息。

在react-router6.0中所有的组件都没有路由信息,也没有withRouter,需要使用hooks语法引入路由信息(history, location, match),所以我们可以自己封装一个withRouter高阶组件。

3.1 新建自己封装的withRouter函数文件withRouter.jsx

由于路由数据是在props中,所以使用属性代理方式,实现自封装的高阶组件。

3.2 在文件中导入自定义路由信息

import { useHistory, useLocation, useRouteMatch} from 'react-router-dom' 

3.3 创建函数式组件,使用hooks语法

function myHoc(OldCom){ return ()=>{ // 返回组件模板 return 
   } } 

3.4 在返回的箭头函数中,使用hooks提供的组合式API,获取路由信息

const history = useHistory() const location = useLocation() const match = useRouteMatch() 

3.5 返回组件模板

return 
   

3.6 导出封装的高阶组件函数

export default myHoc 

3.7 在根组件App.js中导入自己封装的withrouter高阶组件

当使用了hooks新语法,还想使用类组件,就可以使用自己封装的高阶组件来实现。

import withRouter from "./pages/Hooks/withRouter"; 

3.8 在导出根组件时,使用封装的withRouter包裹组件即可传入路由信息

export default withRouter(App); 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/203871.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午9:24
下一篇 2026年3月19日 下午9:24


相关推荐

  • Windows下使用cmd进入MySQL

    Windows下使用cmd进入MySQL安装mysql后使用cmd命令行进入mysql

    2022年6月6日
    56
  • python如何安装numpy

    python如何安装numpy1 根据 python 版本下载相应版本的 numpy 保存至 D ProgramFiles x86 Python Python37 Scripts numpy 下载地址 2 win R 输入 cmd 打开命令行窗口 定位到 python 的安装目录 3 输入 python mpipinstalln 或定位到目录 D ProgramFiles x86 Python Python37 Scripts 输入 pip3 7installnump 1 19 1 cp37 cp37m win

    2026年3月18日
    2
  • C语言FLOAT类型

    C语言FLOAT类型摘录自 CSDN 论坛 点击打开链接问题 1 C 语言规定了 FLOAT 类型 6 7 位的有效数字 取值范围 3 4e 38 至 3 4e38 这个取值范围是从 0 000000000000 至 000000000000 那 1 0 不在这个范围内 不能用 float 定义 2 而且同为 32 位 float 类型比 longint 类型 0 429

    2026年3月18日
    2
  • WorkBuddyClaw实战

    WorkBuddyClaw实战

    2026年3月18日
    2
  • 群晖docker mysql_Watchtower – 群晖自动更新 Docker 映像与容器

    群晖docker mysql_Watchtower – 群晖自动更新 Docker 映像与容器群晖的Docker功能非常丰富,不过也有不完美的地方,映像和容器更新比较麻烦,比如我的Docker容器运行了十几个,如果通过手动更新非常繁琐,容器还需要重新配置本文就介绍如何通过watchtower全自动更新Docker映像,并保留原始配置重新运行容器。watchtower是一个可以监控正在运行的容器镜像是否有更新的工具,当本地镜像与远端镜像有差异的时候,可以自动使用当前容器的运行参数以新镜像重…

    2025年6月13日
    5
  • Linux下QoS模块之tc(traffic control)操作简介/CBQ

    Linux下QoS模块之tc(traffic control)操作简介/CBQLinux 从 kernel nbsp 2 1 105 开始支持 QOS 不过 需要重新编译内核 运行 nbsp make nbsp config 时将 nbsp EXPERIMENTAL OPTIONS nbsp 设置成 nbsp y 并且将 nbsp Class nbsp Based nbsp Queueing nbsp CBQ nbsp Token nbsp Bucket nbsp Flow nbsp Traffic nbsp Shapers nbsp 设置为 nbsp y nbsp 运行 nbsp make nbsp dep nbsp make nbsp clean nbsp ma

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号