1. react高阶组件

1.1 高阶组件的概念

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

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

1.2 高阶组件的使用场景

1.2.1 需要代码重用时

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

1.2.2 需要组件增强优化时

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

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

return (<div><nav><h3>这是高阶组件增加的导航栏</h3></nav><OldCom/></div>)

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 <div><h1>这是订单页的高阶组件</h1></div>// 如果要返回原始组件模板,把原始组件作为子组件返回即可// return <OldCom/>)}}
}
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 (<div><nav><h3>这是高阶组件增加的导航栏</h3></nav><OldCom {...this.tempProps}/></div>
)

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

问题:由于路由中配置的是高阶组件,所以路由信息传入到高阶组件中,原始组件中就没有路由信息了,怎么解决?

  • 因为此时原始组件中已经没有路由信息了,即没有登录状态,可通过登录状态做一个if判断。若无登录状态,则返回空,并在100秒后跳转到登录页,若有登录状态,则返回原始组件模板页面。
console.log("orderHoc", this.props);
if(this.isLogin){return <OldCom/>
}else{setTimeout(()=>{this.props.history.push("/login")}, 100)return ""
}
  • 此时需要在render()函数的返回的原始组件中,动态拼接this.props即可传入路由信息
return (<div><nav><h3>这是高阶组件增加的导航栏</h3></nav><OldCom {...this.props}/></div>
)

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 <div><nav><h3>这是高阶组件中的导航栏</h3></nav>{super.render()}</div>}}
}
export default myHoc

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

return <OldCom/>  // 错误写法

需要使用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 (<OldCom {...newProps} ></OldCom>)}}
}

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

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 (<div><h1>订单页</h1><h2>{this.state.count}<button onClick={this.add}>+</button></h2></div>)}
}
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. 渲染单数据的写法
<button onClick={()=>{setCount(count + 1)  }}>{count}</button>
  1. 渲染对象数据的写法
<button onClick={()=>{state.age ++// setState(state)  // 错误写法setState({ ...state})}}>{state.name}: {state.age}{  // 渲染斗鱼数据state.roomList.map(item=>{return <div key={item.room_id}><img src={item.room_src} alt="" /></div>})}
</button>
  • 修改对象中的状态数据时可以先修改,再拼接上对应的状态名
  1. 使用useState渲染数组中数据的写法
<button onClick={()=>{arr[1] ++// setArr(arr)  // 错误写法,不会更新视图setArr([...arr])
}}>{arr}</button>
  • 注意: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 <OldCom {...tempProps}/>}
}

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

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

3.5 返回组件模板

return <OldCom {...tempProps}/>

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

export default myHoc

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

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

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

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

export default withRouter(App);

react高阶组件和hooks相关推荐

  1. react高阶组件、hooks

    1.高阶组件 1.1概念 高阶组件(简称:HOC):是react中用于重用组件逻辑的高级技术,它本身不是react中的组件,而是一个函数.这个函数接受一个react组件作为参数,并返回一个新组件,实现 ...

  2. react高阶组件和Hooks语法

    高阶组件:本质是一个函数,返回值是一个组件,函数的参数是原生组件,主要是对组件的代码的复用或者是逻辑上的复用, 以及对原始组件上的props和state进行增删改查的操作,也可以对原生组件的进行增强和 ...

  3. 「react进阶」一文吃透React高阶组件(HOC)

    一 前言 React高阶组件(HOC),对于很多react开发者来说并不陌生,它是灵活使用react组件的一种技巧,高阶组件本身不是组件,它是一个参数为组件,返回值也是一个组件的函数.高阶作用用于强化 ...

  4. react 高阶组件hoc使用

    react 高阶组件hoc使用 1. 为什么使用高阶组件 2. 具体使用 2.1原代码: 2.2 使用hoc封装后 1. 为什么使用高阶组件 高阶组件(HOC)是 React 中用于复用组件逻辑的一种 ...

  5. react实现汉堡_利用 React 高阶组件实现一个面包屑导航

    什么是 React 高阶组件 React 高阶组件就是以高阶函数的方式包裹需要修饰的 React 组件,并返回处理完成后的 React 组件.React 高阶组件在 React 生态中使用的非常频繁, ...

  6. [react] 高阶组件(HOC)有哪些优点和缺点?

    [react] 高阶组件(HOC)有哪些优点和缺点? HOC 优点 通过传递props去影响内层组件的状态,不直接改变内层组件的状态,降低了耦合度 缺点 组件多层嵌套, 增加复杂度与理解成本 ref隔 ...

  7. React高阶组件探究

    React高阶组件探究 在使用React构建项目的过程中,经常会碰到在不同的组件中需要用到相同功能的情况.不过我们知道,去这些组件中到处编写同样的代码并不优雅. 在以往,为了解决以上的情况,我们会用到 ...

  8. react组件类型及深入理解react高阶组件

    React中常见的组件类型及分类: 1.展示组件(Presentational component) 与 容器组件(Container component) 2.类组件(Class component ...

  9. React高阶组件_阶段1

    react高阶组件_阶段1 作用: 个人总结的高阶组件设计的作用主要有两点, 这里直接使用装饰器方式 非装饰器使用请结合我的博文"react基础梳理_阶段1"中的"自定义 ...

最新文章

  1. 查看PLC IP 端口_三种方法实现以太网远程访问西门子PLC!
  2. UVA307 Sticks小木棍
  3. IntelliJ idea 给git下来的项目配置python环境(Anaconda)
  4. TypeScript reflect-metadata 结合方法装饰器实现的一个自定义语法检查的例子
  5. mysql导出数据 程序_mysql导出数据
  6. linux 将程序链接到 usr bin,Linux / usr / bin文件在重新启动后消失
  7. 使用pdo,使用pdo无法插入数据怎么办
  8. 基于深度学习的短视频内容分析简介
  9. 俄罗斯方块菜单c语言,飞机游戏、俄罗斯方块、贪吃蛇C语言代码
  10. navicat激活失败
  11. 图片选择器ImagePicker
  12. 编程c 语言怎么表示倍数,C语言里怎么表示是3的倍数
  13. linux小白家教学一
  14. 【程序员学理财】有哪些普通人应该知道的经济学常识?
  15. 【思维题】Bazinga
  16. 用shell脚本写的一个简单的计算器
  17. 虚拟现实,增强现实的安全问题
  18. 将电脑的无线网通过有线分享给其他设备
  19. python pandas修改列名,Python_Pandas学习笔记02:DataFrame获取列名和修改列名
  20. 二元函数偏导数公式_多元函数的偏导数、方向导数、梯度以及微分之间的关系思考...

热门文章

  1. 48.jango09
  2. win10必须禁用的服务_Windows Event Log服务能否关闭?Win10系统Event Log服务详解
  3. Airsim Python API文档整理(1.3.1版本)
  4. mip-img 不启用css,百度mip-img图片详解 如何修改图片MIP
  5. linux安装DM7数据库和初始化实例--无图形界面
  6. WordPress主题_Mancink垂钓渔具爱好者英文网站
  7. 无线视频监控技术持续进步
  8. 编程语言中的 DUCK TYPING|python、c++、java、go
  9. DevOps学习总结
  10. SIP协议与视频通信