简介

高阶组件的概念应该是来源于JavaScript的高阶函数:高阶函数就是接受函数作为输入或者输出的函数。而高阶组件就仅仅是一个接受组件作为输入并返回组件的函数。通常实现高阶组件的方式有两种

  • 属性代理
  • 反向继承

属性代理

属性代理是通过包裹原来的组件来操作props,举个栗子

import React, { Component } from 'React';
//高阶组件定义
const HOC = (WrappedComponent) =>
  class HOC extends Component {
    render() {
      return <WrappedComponent {...this.props} />;
    }
}
//普通的组件
class WrappedComponent extends Component{
    render(){
        //....
    }
}
//高阶组件使用
export default HOC(WrappedComponent)

操作props

图片说明

要传递给WrappedComponent的props先被传递给了HOC,这样HOC就拿到了props的控制权,这也是为什么这种方法叫做属性代理。根据需要,可以对传入的props进行增加,删除,修改。举个栗子

const HOC = (WrappedComponent) =>
    class HOC extends Component {
        render() {
            const newProps = {
                name: 'HOC'
            }
            return <WrappedComponent
                {...this.props}
                {...newProps}
            />;
        }
    }

抽象state

在属性代理的情况下,我们可以将被包裹组件的状态提升到HOC中,一个用法是可以把非受控组件转变成受控组件

class WrappedComponent extends Component {
    render() {
        return <input name="name" {...this.props.name} />;
    }
}

const HOC = (WrappedComponent) =>
    class HOC extends Component {
        constructor(props) {
            super(props);
            this.state = {
                name: '',
            };

            this.onNameChange = this.onNameChange.bind(this);
        }

        onNameChange(event) {
            this.setState({
                name: event.target.value,
            })
        }

        render() {
            const newProps = {
                name: {
                    value: this.state.name,
                    onChange: this.onNameChange,
                },
            }
            return <WrappedComponent {...this.props} {...newProps} />;
        }
    }

反向继承

反向继承是指返回的组件去继承之前的组件,即上述的(WrappedComponent)

const HOC = WrappedComponent=>{
    class HOC extends WrappedComponent{
        render(){
            return super.render();
        }
    }
}

返回的组件继承自WrappedComponent,那么所有的调用将是反向调用(例如:super.render())

渲染劫持

我们可以有意识地控制WrappedComponent的渲染进程,从而控制渲染的结果。例如可以根据参数去决定是否渲染组件

const HOC = (WrappedComponent) =>
  class extends WrappedComponent {
    render() {
      if (this.props.isRender) {
        return super.render();
      } else {
        return null;
      }
    }
  }