关于高阶组件

高阶组件

高阶组件就是一个没有副作用的纯函数,并且可以接收另一个函数组件作为参数,返回值也为一个函数组件。

高阶组件其实就是装饰器模式在 React 中的实现:通过给函数传入一个组件(函数或类)后在函数内部对该组件(函数或类)进行功能的增强(不修改传入参数的前提下),最后返回这个组件(函数或类),即允许向一个现有的组件添加新的功能,同时又不去修改该组件,属于 包装模式(Wrapper Pattern) 的一种。

React 中的高阶组件主要有两种形式:属性代理 和 反向继承

属性代理

// 无状态(函数式组件)
function HigherOrderComponent(WrappedComponent) {
    return props => ;
}
// 有状态
function HigherOrderComponent(WrappedComponent) {
    return class extends React.Component {
        render() {
            return ;
 
        }
    };
}

就是 一个函数接受另一个组件作为参数传入,并返回一个继承了 React.Component 组件的类,且在该类的 render() 方法中返回被传入的 另一个组件。

因为属性代理类型的高阶组件返回的是一个标准的 React.Component 组件,所以在 React 标准组件中可以做什么,那在属性代理类型的高阶组件中就也可以做什么,比如:

  • 操作 props

    可以为子组件添加一些属性

  • 抽离 state

    利用 props 和回调函数把 state 抽离出来,可以实现受控组件

  • 通过 ref 访问到组件实例

  • 用其他元素包裹传入的组件

    比如再包一层div什么的

反向继承

function HigherOrderComponent(WrappedComponent) {
    return class extends WrappedComponent {
        render() {
            return super.render();
        }
    };
}

反向继承其实就是 一个函数接受另一个组件作为参数传入,并返回一个继承了该传入组件的类,且在该类的 render() 方法中返回 super.render() 方法。

反向继承可以用来做什么:

  • 操作 state

    高阶组件中可以读取、编辑和删除传入组件实例中的 state。甚至可以增加更多的 state 项,但是 非常不建议这么做因为这可能会导致 state 难以维护及管理

  • 渲染劫持(Render Highjacking)

    • 有条件地展示元素树(element tree)
    • 操作由 render() 输出的 React 元素树
    • 在任何由 render() 输出的 React 元素中操作 props
    • 用其他元素包裹传入的组件 WrappedComponent (同 属性代理)

其实属性代理和反向继承的实现有些类似的地方,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component,反向继承中继承的是传入的组件。

高阶组件存在的问题

  • 静态方法丢失

    因为原始组件被包裹于一个容器组件内,也就意味着新组件会没有原始组件的任何静态方法

  • refs 属性不能透传

    如果你向一个由高阶组件创建的组件的元素添加 ref 引用,那么 ref 指向的是最外层容器组件实例的,而不是被包裹的组件。

  • 反向继承不能保证完整的子组件树被解析

    我们知道反向继承的渲染劫持可以控制传入组件 的渲染过程,也就是说这个过程中我们可以对 elements tree、state、props 或 render() 的结果做各种操作。但是如果渲染 elements tree 中包含了 function 类型的组件的话,这时候就不能操作组件的子组件了。

应用场景

权限控制

利用高阶组件的 条件渲染 特性可以对页面进行权限控制

组件渲染性能追踪

借助父组件子组件生命周期规则捕获子组件的生命周期,可以方便的对某个组件的渲染时间进行记录

页面复用

高阶组件的约定

  • props 保持一致
  • 你不能在函数式(无状态)组件上使用 ref 属性,因为它没有实例
  • 不要以任何方式改变原始传入组件
  • 不要透传不相关 props 属性给被包裹的组件
  • 不要再 render() 方法中使用高阶组件
  • 使用 compose 组合高阶组件
  • 包装显示名字以便于调试

你可能感兴趣的:(关于高阶组件)