React 中高阶组件的基本使用

954 阅读2分钟

前言

不学不知道,一学吓一跳。这react跟vue相比,真是太能融合了。就拿这个高阶组件来说,里面融合了函数式组件,类组件,兄弟组件的状态提升,父子组件传值。还用到了函数柯里化这个思想,真是太牛X了,下面我们就一步一步来学习高阶组件的使用.

  • 下面以一个demo来使用高阶组件完成:移动鼠标,图案跟着鼠标进行移动,并且在页面实时显示移动坐标

高阶组件的基本使用步骤

创建一个函数,名称预定以width开头

function widthMouse() {
  
}

指定函数的参数,参数以大写字母开头,作为要渲染的组件

function widthMouse(WrapCopmonent) {

}

在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回

function widthMouse(WrapComponent) {
  class Mouse extends React.Component {

  }
  return Mouse
}

提供复用的状态逻辑代码

  • 状态:鼠标移动的坐标
  • 逻辑: 根据鼠标的移动,对移动的坐标进行实时的更新
  • 优化:在页面销毁时,将事件进行销毁
function widthMouse(WrapComponent) {
  class Mouse extends React.Component {
    state = {
      x: '',
      y: ''
    }
    handleMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }
    componentDidMount() {
      window.addEventListener('mousemove', this.handleMove)
    }
    componentWillUnmount() {
      window.addEventListener('mousemove', this.handleMove)
    }
  }
  return Mouse
}

在该组件中,渲染参数组件,同时将状态通过props传给参数组件

function widthMouse(WrapComponent) {
  class Mouse extends React.Component {
    state = {
      x: '',
      y: ''
    }
    handleMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }
    componentDidMount() {
      window.addEventListener('mousemove', this.handleMove)
    }
    componentWillUnmount() {
      window.addEventListener('mousemove', this.handleMove)
    }
    render() { 
      return (
        <div>
          <WrapComponent {...this.state} />
        </div>
      )
    }
  }

  return Mouse
}

调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件并将其渲染到页面

// 测试高阶组件- 实现实时显示鼠标移动坐标
import img from './favicon.ico'
const Position = (props) => {
  return (
    <div>
      x坐标 {props.x}
      <br />
      y坐标 {props.y}
    </div>
  )
}
const MousePosition = widthMouse(Position)
// 测试高阶组件- 实现图片随鼠标移动
const Logo = (props) => {
  return (
    <img src={img} style={{
      position: 'absolute',
      top: props.y,
      left: props.x
    }} />
  )
}
const MouseLogo = widthMouse(Logo)
class App extends React.Component {
  render() {
    return (
      <div>
        <h1>高阶组件</h1>
        <MousePosition />
        <MouseLogo />
      </div>

    )
  }
}
ReactDOM.render(<App />, document.getElementById('root'))

使用react调试工具,你会发现,由于Position和Logo两个组件都是通过高阶组件widthMouse来包装的,所以名字都一样,那我们可以通过displayName来设置组件名

Mouse.displayName = `widthMouse${getDisplayName(WrapComponent)}`

function getDisplayName(WrapComponent) {
  return WrapComponent.displayName || WrapComponent.name || 'Component'
}

props传递

  • 由于我们只是在接收高阶函数传来的值,那如果我想给高阶函数传递值,该怎么办呢
class App extends React.Component {
  render() {
    return (
      <div>
        <h1>高阶组件</h1>
        <MousePosition a="props传递"/>
        <MouseLogo />
      </div>

    )
  }
}

  • 首先他是传递了,是传递到函数内部创建一个类组件Mouse里了,但是在渲染参数组件的时候,没有=继续往下传,那我们在渲染参数组件的时候,给他传递进去就ok了
 <WrapComponent {...this.state} {...this.props} />

所有代码

import img from './favicon.ico'

function widthMouse(WrapComponent) {
  class Mouse extends React.Component {
    state = {
      x: '',
      y: ''
    }
    handleMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }
    componentDidMount() {
      window.addEventListener('mousemove', this.handleMove)
    }
    componentWillUnmount() {
      window.addEventListener('mousemove', this.handleMove)
    }
    render() {
      return (
        <div>
          <WrapComponent {...this.state} {...this.props} />
        </div>
      )
    }
  }
  Mouse.displayName = `widthMouse${getDisplayName(WrapComponent)}`

  return Mouse
}
function getDisplayName(WrapComponent) {
  return WrapComponent.displayName || WrapComponent.name || 'Component'
}
// 测试高阶组件- 实现实时显示鼠标移动坐标
const Position = (props) => {
  return (
    <div>
      x坐标 {props.x}
      <br />
      y坐标 {props.y}
    </div>
  )
}
// 测试高阶组件- 实现图片随鼠标移动
const Logo = (props) => {
  return (
    <img src={img} style={{
      position: 'absolute',
      top: props.y,
      left: props.x
    }} />
  )
}
const MouseLogo = widthMouse(Logo)
const MousePosition = widthMouse(Position)
class Appp extends React.Component {
  render() {
    return (
      <div>
        <h1>高阶组件</h1>
        <MousePosition a="props传递" />
        <MouseLogo />
      </div>

    )
  }
}
ReactDOM.render(<Appp />, document.getElementById('root'))

总结

  1. 高阶组件是将函数式组件和类组件的一种融合,配得上这个名字HOC
  2. 函数柯里化的编程思想在高阶组件中的表现太优秀了
  3. 组件的传值是基础,在这基础之上的传值的再次融合,写的太有意思了