高阶函数和高阶组件

1,450 阅读3分钟

高阶函数:接受函数作为参数的函数,其实map函数就是一个高阶函数

高阶组件:不是React提供的某种API,而是使用React的一种模式,类似于高阶函数,即指接受React组件作为参数,输出一个新的组件的函数。在这个函数中,我们可以修饰组件的props与state,所以在一些特定情况下高阶组件可以让我们的代码看起来更优美。

注:返回的新组件拥有了输入组件所不具备的功能。这里提到的组件并不是组件实例,而是组件类,也可以是一个无状态组件的函数

作用:

  • 更具有复用性:有时候很多React组件都需要公用同样一个逻辑,比如React-Redux中容器组件的部分,没有必要让每个组件都实现一遍shouldComponentUpdate这些生命周期函数,把这部分逻辑提取出来,利用高阶组件的方式应用出去,就可以减少很多组件的重复代码。
  • 修改现有React组件的行为:有些现成的React组件并不是开发者自己开发的,来自于第三方,或者即便是我们自己开发的,但是我们不想去触碰这些组件的内部逻辑,这时候可以用高阶组件。通过一个独立于原有组件的函数,可以产生新的组件,对原有组件没有任何侵害。

目前,高阶组件的实现方式主要有两种:

  • 代理方式的高阶组件:高阶组件通过被包裹的React组件来操作props
    • 高阶组件中可以修饰props于state的,在高阶组价中定义state,作为props传给参数组件(InnerComponent)
    • 高阶组件也可以传方法到参数组件(InnerComponent)中
    • 高阶组件的生命周期不会影响传入的组件
    • 并不是高阶组件的所有生命周期都会先执行
    • 由同一个高阶组件生成的新的组件间其实是相互不会影响的
  • 继承方式的高阶组件:高阶组件继承于被包裹的React组件
    • 操纵props
    • 操纵生命周期

代理方式实例

const HOC = (InnerComponent) => class extends React.Component{
    static defaultProps = {
        n:'HOC'
    }
    constructor(){
        super();
        this.state = {
            count:0
        }
    }
    componentWillMount(){
        console.log('HOC will mount')
    }
    componentDidMount(){
        console.log('HOC did mount')
    }
    update = () =>{
        const {count} = this.state
        this.setState({
            count:count+1
        })
    }
    render(){
        const newProps = this.state;
        return(
            <InnerComponent
                {...this.props}
                {...newProps}   //传state
                update = {this.update}  //传方法
            />
        )
    }

}

//无状态组件
const Button = HOC((props) => <button onClick={props.update}>{props.children}-{props.count}</button>) //无状态组件

//Button中改变count,不会影响Label组件中的count
class Label extends React.Component{//传统组件
    static defaultProps = {
        n:'C'
    }
    componentWillMount(){
        console.log('C will mount')
    }
    componentDidMount(){
        console.log('C did mount')
    }
    render(){
        return(
            <label>{this.props.children}-{this.props.count}</label> 
        )
    }
}
const LabelHoc = HOC(Label)

class App extends React.Component{//根组件
    render(){
        return(
            <div>
            	//随着点击渲染出label-0、1、2.....
                <Button>button</Button>
                <br/>
                //渲染出:label-0
                <LabelHoc>label</LabelHoc>
            </div>
        )
    }
}

继承方式实例

const HOC = (WrappedComponent) => 
  class NewComp extends WrappedComponent {
    componentWillMount() {
      console.log('我是继承高阶组件中的生命周期')
    }
    render() {
      // 获取继承而来的传入组件的元素内容
      const element = super.render()
      const newStyle = {
        color:element.type === 'div' ? 'red' : 'yellow'
      }
      const newProps = {...this.props, style: newStyle}
      // React.cloneElement方法生成新的React对象
      return React.cloneElement(element, newProps, element.props.children)
  }
}
export default HOC

普通组件传入高级组件

@HOC
class A extends Component {
  componentWillMount() {
    console.log('我是普通组件中生命周期')
  }
  render() {
    return (
      <div>我是普通组件</div>
    )
  }
}

export default A

最终效果:div是红色 ———— 这是操纵props实例

输出:我是继承高阶组件中的生命周期(A中生命周期内容不见了,被继承高阶组件给劫持了) ———— 
这就是继承高阶组件操纵生命周期