13.高阶组件

什么是高阶组件?在学习高阶组件之前,很多人都听说过高阶函数,其实高阶函数和高阶组件非常相似。

回顾一下高阶函数:

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

    • 接收一个或多个函数作为输入
    • 输出一个函数
  • JavaScript中比较常见的filter、map、reduce都是高阶函数
13.1什么是高阶组件

那么什么是高阶组件?

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

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

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

高阶组件的编写:

function enhanceComponent(WraperComponent,) {
  return class NewComponent extends PureComponent {
    render() {
      return (
        <WraperComponent {...this.props} />
      )
    }
  }
}

高阶组件的调用:

const NewComponent = enhanceComponent(App);

在给高阶组件传递数据时需要在高阶组件内部进行接收

关于组件名称
  • 在es6中,类表达式中类名是可以省略的。(函数也是一样)

React组件化开发(6)- 高阶组件(6)

  • 组件的名称都可以通过displayName来修改,(在React developer tools)里可以看到React组件化开发(6)- 高阶组件(6)

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

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

  • 比如redux中的connect;
  • 比如react-router中的withRouter
13.3高阶组件的应用
一:增强props
import React, { PureComponent } from 'react'

class Home extends PureComponent {

  render() {
    console.log(this.props);
    return (
      <h2>Home:{`昵称:${this.props.nickName},等级:${this.props.level} 区域:${this.props.region}`}</h2>
    )
  }
}

class Footer extends PureComponent {
  render() {
    return (
      <h2>Footer:{`昵称:${this.props.nickName},等级:${this.props.level} 区域:${this.props.region}`}</h2>
    )
  }
}

function enhanceRegion(WraperComponent) {
  return class NewComponent extends PureComponent {
    render() {
      return <WraperComponent {...this.props} region="中国" />
    }
  }
}

const EnhanceHome = enhanceRegion(Home);
const EnhanceFooter = enhanceRegion(Footer);

export default class App extends PureComponent {
  constructor() {
    super();

  }
  render() {
    return (
      <div>
        App
        <EnhanceHome nickName="库里" level={90} />
        <EnhanceFooter nickName="追梦格林" level={80} />
      </div>
    )
  }
}
二:增强props默认
import React, { PureComponent, createContext } from 'react'


function Home() {
  return (
    <UserInfo.Consumer>
      {
        props => {
          return (<div><h2>Home:{`昵称:${props.nickName},等级:${props.level},地区:${props.Region}`}</h2></div>)
        }
      }
    </UserInfo.Consumer>
  )
}

function About() {
  return (
    <UserInfo.Consumer>
      {
        props => {
          console.log(props);
          return (<div><h2>About:{`昵称:${props.nickName},等级:${props.level},地区:${props.Region}`}</h2></div>)
        }
      }
    </UserInfo.Consumer>
  )
}

const UserInfo = createContext({
  nickName: '默认名字',
  level: "默认等级",
  地区: "默认地区"
});

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <UserInfo.Provider value={{ nickName: "斯蒂芬库里", level: 99, Region: "中国" }}>
          <Home />
          <About />
        </UserInfo.Provider>
      </div>
    )
  }
}
三:增强props改进
import React, { PureComponent, createContext } from 'react'


const UserInfo = createContext({
  nickName: "默认名",
  level: "默认等级",
  Region: "默认地区"
})


function Home(props) {
  console.log(props);
  return (
    <div><h2>Home:{`昵称:${props.nickName},等级:${props.level},地区:${props.Region}`}</h2></div>
  )
}

function About(props) {
  return (
    <div><h2>About:Home:{`昵称:${props.nickName},等级:${props.level},地区:${props.Region}`}</h2></div>
  )
}


// 定义高阶组件
function enhanceRegion(WrappedComponent) {

  return props => {
    return (
      <UserInfo.Consumer>
        {
          data => {
            return <WrappedComponent {...data} />
          }
        }
      </UserInfo.Consumer>
    )
  }
}

const EnhanceHome = enhanceRegion(Home);
const EnhanceAbout = enhanceRegion(About);

EnhanceHome()
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <UserInfo.Provider value={{ nickName: "斯蒂芬库里", level: 99, Region: "中国" }}>
          <EnhanceHome />
          <EnhanceAbout />
        </UserInfo.Provider>
      </div>
    )
  }
}
四:登录鉴权操作
import React, { PureComponent } from 'react'


function CartPage() {
  return <h2>购物车页面</h2>
}

function LoginPage() {
  return <h2>需要登录</h2>
}

// 高阶组件

function enhanceIsLogin(WrappedComponent) {
  const Cpn = props => {
    // console.log(props);
    if (props.isLogin) {
      return <WrappedComponent />
    } else {
      return <LoginPage />
    }
  }
  return Cpn;
}

const CartAuth = enhanceIsLogin(CartPage);


export default class extends PureComponent {
  render() {
    return (
      <div>
        <CartAuth isLogin={false} />
      </div>
    )
  }
}
五:生命周期劫持
import React, { PureComponent } from 'react'

class Home extends PureComponent {
  render() {
    return (
      <h2>Home</h2>
    )
  }


}

function enhanceMountTime(WrapeedComponent) {
  const NewCpn = class extends PureComponent {
    UNSAFE_componentWillMount() {
      this.WillMoutTime = Date.now();

    }
    componentDidMount() {
      this.DitMoutTime = Date.now();
      const MountTime = this.DitMoutTime - this.WillMoutTime;
      console.log(`${WrapeedComponent.name}渲染时间是:${MountTime}`);
    }
    render() {
      return <WrapeedComponent {...this.props} />
    }
  }

  return NewCpn
}


class About extends PureComponent {
  render() {
    return (
      <h2>About</h2>
    )
  }
}

const MountTimeHome = enhanceMountTime(Home);
const MountTimeAbout = enhanceMountTime(About);

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <h3>App</h3>
        {/* 计算一个组件创建到挂载完毕的时间 */}
        <MountTimeHome />
        <MountTimeAbout />
      </div>
    )
  }
}
13.4高阶组件的意义

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

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

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

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

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

Hooks的出现,是开创性的,它解决了很多React之前的存在的问题

  • 比如this指向问题、比如hoc的嵌套复杂度问题等等;
文章目录