react高阶组件

274 阅读2分钟

什么是高阶组件?

一个高阶组件只是一个包装了另外一个 React 组件的 React 组件。

高阶组件可以做什么?

  • 代码复用,逻辑抽象,抽离底层准备(bootstrap)代码
  • 渲染劫持
  • State 抽象和更改
  • Props 更改

如何实现高阶组件

  • 1.属性代理
  • 2.反向继承

属性代理

function HOC(WrappedComponent){
    return class HOC extends Component {
        render(){
            const newProps = {type:'HOC'};
            return <div>
                <WrappedComponent {...this.props} {...newProps}/>
            </div>
        }
    }
}
@HOC
class OriginComponent extends Component {
    render(){
        return <div>这是原始组件</div>
    }
}
//const newComponent = HOC(OriginComponent)

Props Proxy 可以做什么?

  • 更改 props
  • 通过 refs 获取组件实例
  • 抽象 state
  • 把 WrappedComponent 与其它 elements 包装在一起

上面的例子是使用属性代理的方法,增加了一个props属性

反向继承

function HOC(WrappedComponent){
    return class HOC extends WrappedComponent {
        //继承了传入的组件
        test1(){
            return this.test2() + 5;
        }
        componentDidMount(){
            console.log('1');
            this.setState({number:2});
        }

        render(){
            //使用super调用传入组件的render方法
            return super.render();
        }
    }
}
@HOC
class OriginComponent extends Component {
    constructor(props){
        super(props);
        this.state = {number:1}
    }
    test2(){
        return 4;
    }
    componentDidMount(){
        console.log('2');
    }
    render(){
        return (
            <div>
                {this.state.number}{'and'}
                {this.test1()}
                这是原始组件
            </div>
        )
    }
}
//const newComponent = HOC(OriginComponent)

上述例子使用了方向代理,为何叫反向继承呢,因为OriginComponent是被动的被HOC继承,反向继承可以做劫持渲染

可以用反向继承高阶组件做什么?

  • 渲染劫持(Render Highjacking)
  • 操作 state

你无法更改或创建 props 给 WrappedComponent 实例,因为 React 不允许变更一个组件收到的 props,但是你可以在 render 方法里更改子元素/子组件们的 props。

例子1:条件性渲染。如果 this.props.loggedIn 是 true,这个高阶组件会原封不动地渲染 WrappedComponent,如果不是 true 则不渲染(假设此组件会收到 loggedIn 的 prop)

function iiHOC(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      if (this.props.loggedIn) {
        return super.render()
      } else {
        return null
      }
    }
  }
}

参考