高阶组件HOC
高阶函数的定义,至少满足以下条件之一:
- 接受一个或多个函数作为输入
- 输出一个函数
JavaScript中比较常见的filter、map、reduce都是高阶函数
那么什么是高阶组件呢?
- 高阶组件的英文是 Higher-Order Compoents,简称HOC
- 官方的定义:高阶组件是参数为组件,返回值为新组件的函数
- 高阶组件本身不是一个组件,而是一个函数
- 这个函数的参数是一个组件,返回值也是一个组件
高阶组件并不是React API的一部分,它是基于React的组合特性而形成的设计模式
高阶组件在一些React第三方库中非常常见:
- rudux 中的connect
高阶组件应用-props增强
import React, { PureComponent } from 'react'
// 定义组件: 给一些需要特殊数据的组件, 注入props
function enhancedUserInfo(OriginComponent, otherProps = {}) {
class NewComponent extends PureComponent {
constructor(props) {
super(props)
this.state = {
userInfo: {
name: "jay chou",
age: 40
}
}
}
render() {
return <OriginComponent {...this.props} {...this.state.userInfo} {...otherProps}/>
}
}
return NewComponent
}
const Home = enhancedUserInfo(function(props) {
return <h1>Home: {props.name}-{props.age}-{props.banners}</h1>
})
const User = enhancedUserInfo(function(props) {
return <h1>Profile: {props.name}-{props.age}-{props.height}</h1>
}, {height: 174})
export class App extends PureComponent {
render() {
return (
<div>
<Home banners={["轮播1", "轮播2"]}/>
<User/>
</div>
)
}
}
export default App
高阶组件应用-共享Context
import React, { PureComponent } from 'react'
import { createContext } from "react"
const ThemeContext = createContext({color: '#f40'})
function withTheme(OriginComponment) {
return (props) => {
return (
<ThemeContext.Consumer>
{
value => <OriginComponment {...value} {...props}/>
}
</ThemeContext.Consumer>
)
}
}
class Product extends PureComponent {
render() {
const {color, size} = this.props
return (
<div>
<h1>Product: {color}-{size}</h1>
</div>
)
}
}
const NewProduct = withTheme(Product)
export class App extends PureComponent {
render() {
return (
<div>
<ThemeContext.Provider value={{color: "blue", size: 30}}>
<NewProduct />
</ThemeContext.Provider>
</div>
)
}
}
export default App
高阶组件应用-登录鉴权
在开发中,有些页面是需要用户登录后才能进入的
import React, { PureComponent } from 'react'
const loginAuth = function(OriginComponment) {
return (props) => {
const token = localStorage.getItem("token")
if(token) {
return <OriginComponment {...props}></OriginComponment>
}
return <div>您尚未登录,不能查看该页面</div>
}
}
const User = loginAuth(function() {
return (
<div>User Page</div>
)
})
export class App extends PureComponent {
constructor() {
super()
this.state = {
isLogin: false,
}
}
loginClick() {
localStorage.setItem("token", "jshjbhdasjk")
this.setState({ isLogin: true }) //高阶组件没有使用memo 所以会重新渲染
// this.forceUpdate() //强制更新
}
render() {
return (
<div>
<button onClick={e => this.loginClick()}>登录</button>
<User />
</div>
)
}
}
export default App
高阶组件应用-生命周期劫持
import { PureComponent } from "react";
function logRenderTime(OriginComponent) {
return class extends PureComponent {
UNSAFE_componentWillMount() {
this.beginTime = new Date().getTime()
}
componentDidMount() {
this.endTime = new Date().getTime()
const interval = this.endTime - this.beginTime
console.log(`当前${OriginComponent.name}页面花费了${interval}ms渲染完成!`)
}
render() {
return <OriginComponent {...this.props}/>
}
}
}
class Detail extends PureComponent {
render() {
return (
<div>
<h2>Detail Page</h2>
<ul>
<li>数据列表1</li>
<li>数据列表2</li>
<li>数据列表3</li>
<li>数据列表4</li>
<li>数据列表5</li>
<li>数据列表6</li>
<li>数据列表7</li>
<li>数据列表8</li>
<li>数据列表9</li>
<li>数据列表10</li>
</ul>
</div>
)
}
}
const NewDetail = logRenderTime(Detail)
class App extends PureComponent {
render() {
return (
<div>
<NewDetail />
</div>
)
}
}
export default App
高阶组件的意义
利用高阶组件可以针对某些React代码进行更优雅的处理
在React早期时提供另一种代码复用方式 mixin,目前不再建议使用
- Mixin 可能会相互依赖,相互耦合,不利于代码维护
- 不同的Mixin中的方法可能会互相冲突
- Mixin非常多时,组件处理起来会比较麻烦,甚至还要为其做相关处理,这样会给代码造成滚雪球式的复杂性
当然,HOC也有自己的一些缺陷
- HOC需要在原组件上进行包裹或者嵌套,如果使用大量的HOC,将会产生非常多的嵌套,这让调试变得非常困难
- HOC可以劫持props,在不遵守约定的情况下也可能造成冲突
Hooks的出现,是开创性的,它解决了很多React之前存在的问题
- 比如this指向问题、HOC嵌套的复杂度问题等