React 高阶组件

110 阅读2分钟

高阶组件(HOC Higher-Order Component):高阶组件是参数为组件,返回值为新组件的函数。

也就是一个函数,接收要包装的组件,返回增强后的组件。

const EnhancedComponent = higherOrderComponent(WrappedComponent);

higherOrderComponent: 高阶组件,是一个函数
WrappedComponent: 要包装的组件
EnhancedComponent: 包装之后的增强组件,

组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。

创建一个高阶组件

// 创建高阶组件
// 1. 约定 名称以 with 开头
// 2. 约定参数名称以大写字母开头,因为其实是个组件
function withMouse(WrappedComponent) {
  // 3. 创建一个类组件
  class Mouse extends React.Component {
    // 4. 在类组件中,提供要复用的状态和方法
    state = {
      x: 0,
      y: 0,
    };

    componentDidMount() {
      window.addEventListener('mousemove', this.handleMouseMove);
    }

    componentWillUnmount() {
      window.removeEventListener('mousemove', this.handleMouseMove);
    }

    handleMouseMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY,
      });
    };

    render() {
      // props 可以访问到 age属性
      console.log('mouse', this.props)
      // return <WrappedComponent {...this.state} />;
      return <WrappedComponent {...this.state} {...this.props} />;
    }
  }


  // 设置 displayName 是为了调试区分
  Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`;

  // 5. 将新组件返回
  return Mouse;
}

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

const MouseTracker = props => {
  // 高阶组件没有传递时 获取不到 age 属性
  // 传递之后可以获取到了
  console.log('mouseTracker', props)
  return (
    <div>
      <h1>高阶组件</h1>
      当前坐标是:{props.x}, {props.y}
    </div>
  )
}


// 调用高阶组件得到增强后的组件
const EnhancedMouse = withMouse(MouseTracker);

export default EnhancedMouse;

关于设置 displayName,是为了便于调试,因为通过高阶组件包装之后的组件名称都一样,不利于 通过 react developer 工具调试, 下面是官方推荐的方式

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

关于高阶组件 props 丢失问题

<HighRanking.HighHoc age={20}></HighRanking.HighHoc>

在使用高阶组件时,传递了 age 属性,但是在 MouseTracker 组件中获取不到,因为在 withMouse 组件中,没有继续往下传递 props 造成的,只需要继续往下传即可。

withMouse 中 mouse 组合中的render改成如下代码即可
render() {
  // props 可以访问到 age属性
  console.log('mouse', this.props)
  return <WrappedComponent {...this.state} {...this.props} />;
}