React解密:React高阶组件是什么?

React中比较高大上的东西,高阶组件应该算是一个点,开发中也许写的不多,但是我们必须要直到高阶组件是什么,高阶组件能干什么?

A higher-order component is a function that takes a component and returns a new component.

这是react官网给出的解释,也就是说,高阶组件就是接收一个组件,然后返回一个新组件。这是函数式编程的思想。那么高阶组件是如何实现的呢?俩种方法:属性代理和反向继承。

属性代理:实质就是通过包裹原来的组件来操作props;

import React, { Component } from 'react'

const HOC = (WrappedComponent) =>
  class WrapperComponent extends Component {
    render() {
      return <WrappedComponent {...this.props} />;
    }
}
//普通的组件
class WrappedComponent extends Component{
    render(){
        //....
    }
}
//高阶组件使用
export default HOC(WrappedComponent)

我们可以看到,原封不动的返回了WrappedComponent组件。

操作props:

我们看到之前要传递给被包裹组件WrappedComponent的属性首先传递给了高阶组件返回的组件(WrapperComponent),这样我们就获得了props的控制权(这也就是为什么这种方法叫做属性代理)。我们可以按照需要对传入的props进行增加、删除、修改(当然修改带来的风险需要你自己来控制)

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

为被包裹组件(WrappedComponent)新增加了固定的name属性,因此WrappedComponent组件中就会多一个name的属性。

获取ref:在属性代理中,可以轻松的拿到被包裹的组件的实例引用(ref)

import React, { Component } from 'React';
 
const HOC = (WrappedComponent) =>
    class wrapperComponent extends Component {
        storeRef(ref) {
            this.ref = ref;
        }
        render() {
            return <WrappedComponent
                {...this.props}
                ref = {::this.storeRef}
            />;
        }
    }

wrapperComponent渲染接受后,我们就可以拿到WrappedComponent组件的实例,进而实现调用实例方法的操作(当然这样会在一定程度上是反模式的,不是非常的推荐)。

抽象state:属性代理的情况下,我们可以将被包裹组件(WrappedComponent)中的状态提到包裹组件中,一个常见的例子就是实现不受控组件受控的组件的转变.

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

const HOC = (WrappedComponent) =>
    class 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 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;
      }
    }
  }

在反向继承中,我们可以做非常多的操作,修改state、props甚至是翻转Element Tree。反向继承有一个重要的点: 反向继承不能保证完整的子组件树被解析。

  • 元素(element)是一个是用DOM节点或者组件来描述屏幕显示的纯对象,元素可以在属性(props.children)中包含其他的元素,一旦创建就不会改变。我们通过JSXReact.createClass创建的都是元素。
  • 组件(component)可以接受属性(props)作为输入,然后返回一个元素树(element tree)作为输出。有多种实现方式:Class或者函数(Function)。

  所以, 反向继承不能保证完整的子组件树被解析的意思的解析的元素树中包含了组件(函数类型或者Class类型),就不能再操作组件的子组件了,这就是所谓的不能完全解析

总的来说:

高阶组件属于函数式编程(functional programming)思想,对于被包裹的组件时不会感知到高阶组件的存在,而高阶组件返回的组件会在原来的组件之上具有功能增强的效果。而Mixin这种混入的模式,会给组件不断增加新的方法和属性,组件本身不仅可以感知,甚至需要做相关的处理(例如命名冲突、状态维护),一旦混入的模块变多时,整个组件就变的难以维护,也就是为什么如此多的React库都采用高阶组件的方式进行开发。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值