React-高阶组件

高阶组件是 React 中复用组件逻辑的一种技巧,高阶组件是一个函数,接收需要包装的组件,返回值为增强后的组件。

实现思路:

高阶组件内部创建一个类组件,在这个类组件中去提供复用状态的逻辑代码,通过 prop 将复用的状态组件传递给被包装组件。

创建高阶组件步骤:

  1. 创建一个函数,名称约定以 with 开头

  2. 给函数设置形参用于接收传过来的组件,参数以大写字母开头(作为参数组件使用)

  3. 在函数内部创建一个类组件,在类组件中提供复用的状态逻辑代码;并将类组件作为返回值返回

  4. 在类组件中渲染参数组件,同时将类组件的状态通过 prop 传递给参数组件

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

示例:

import React from 'react'
import ReactDOM from 'react-dom'

import img from './images/tianshi.gif'

// 高阶组件
function withMouse (WrappedComponent) {
  // 类组件
  class Mouse extends React.Component {
    // 状态
    state = {
      x: 0,
      y: 0
    }

    handleMouseMove = e => {
      // 修改状态
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }

    render () {
      console.log(this.props)
      // 将当前组件的 state 传递给传入的需要包装的组件
      return <WrappedComponent {...this.state}></WrappedComponent>
    }
	// 组件挂载后注册鼠标移动事件
    componentDidMount () {
      window.addEventListener('mousemove', this.handleMouseMove)
    }
    // 卸载组件时解绑鼠标移动事件
    componentWillUnmount () {
      window.removeEventListener('mousemove', this.handleMouseMove)
    }
  }

  return Mouse
}
// 测试高阶组件1
const Test = props => {
  console.log('Test:', props)
  return (
    < p > x: {props.x}, y: {props.y}</p >
  )
}
// 测试高阶组件2
const Cat = props => (
  <img
    src={img}
    alt="cat"
    style={{
      position: 'absolute',
      top: props.y - 64,
      left: props.x - 64
      width: 128,
      height: 128
    }} />
)

// 调用高阶组件,获取返回后的包装组件
const MouseTest = withMouse(Test)
const MouseCat = withMouse(Cat)

// 根组件
class App extends React.Component {
  render () {
    return (
      <div>
        <h1>App 组件</h1>
        {/* 使用包装后的组件 */}
        <MouseTest www="123456"></MouseTest>
        <MouseCat></MouseCat>
      </div>
    )
  }
}

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

React-高阶组件_第1张图片
使用高阶组件实现了组件复用但是会存在组件名称相同的问题,这是因为 react 默认使用组件的名称作为 displayName

解决办法:为高阶组件设置 displayName 来区分不同的组件,便于设置调试信息

//设置类组件的 displayName
Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`

// 获取组件名称
function getDisplayName (WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

高阶组件不会向下传递 props 所以会存在 props 丢失的问题

解决办法:在类组件渲染 WrappedComponent 时,将 statethis.props 一起传递给组件

render () {
   console.log('Mouse 组件的 props:', this.props)
   // 将当前组件的 props 向下传递
   return <WrappedComponent {...this.state} {...this.props}></WrappedComponent >
}

最终完整代码:

import React from 'react'
import ReactDOM from 'react-dom'

import img from './images/tianshi.gif'

// 高阶组件
function withMouse (WrappedComponent) {
  // 类组件
  class Mouse extends React.Component {
    // 状态
    state = {
      x: 0,
      y: 0
    }

    handleMouseMove = e => {
      // 修改状态
      this.setState({
        x: e.clientX,
        y: e.clientY
      })
    }

    render () {
      console.log(this.props)
      // 将当前组件的 state 和 props传递给传入的需要包装的组件
      return <WrappedComponent {...this.state} {...this.props}></WrappedComponent>
    }
	// 组件挂载后注册鼠标移动事件
    componentDidMount () {
      window.addEventListener('mousemove', this.handleMouseMove)
    }
    // 卸载组件时解绑鼠标移动事件
    componentWillUnmount () {
      window.removeEventListener('mousemove', this.handleMouseMove)
    }
  }
  //设置类组件的 displayName
  Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`

  // 获取组件名称的函数
  function getDisplayName (WrappedComponent) {
    return WrappedComponent.displayName || WrappedComponent.name || 'Component'
  }
  
  return Mouse
}
// 测试高阶组件1
const Test = props => {
  console.log('Test:', props)
  return (
    < p > x: {props.x}, y: {props.y}</p >
  )
}
// 测试高阶组件2
const Cat = props => (
  <img
    src={img}
    alt="cat"
    style={{
      position: 'absolute',
      top: props.y - 64,
      left: props.x - 64
      width: 128,
      height: 128
    }} />
)

// 调用高阶组件,获取返回后的包装组件
const MouseTest = withMouse(Test)
const MouseCat = withMouse(Cat)

// 根组件
class App extends React.Component {
  render () {
    return (
      <div>
        <h1>App 组件</h1>
        {/* 使用包装后的组件 */}
        <MouseTest www="123456"></MouseTest>
        <MouseCat></MouseCat>
      </div>
    )
  }
}

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

React-高阶组件_第2张图片

你可能感兴趣的:(React)