您现在的位置是:首页 > 正文

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

2024-01-30 21:36:48阅读 0

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库都采用高阶组件的方式进行开发。

网站文章

  • Django安装

    Django安装

    我们使用anaconda真实环境创建项目,这样可以更快的完成将来项目的创建一、环境配置(没有配置的同学需要进行操作)1.1查询anaconda环境1.1.1点击anaconda命令窗口1.1.2在命令...

    2024-01-30 21:36:41
  • 快速排序java练习

    快速排序java练习

    快速排序是一种高效的排序算法,其基本思想是通过一趟排序将待排序列分割成独立的两部分,其中一部分的所有元素都比另一部分的所有元素小,然后再分别对这两部分进行排序,最终得到一个有序序列。其具体实现如下:1...

    2024-01-30 21:36:11
  • 现代浏览器内部机制 Part 4 | 事件

    现代浏览器内部机制 Part 4 | 事件

    原文:Inside Look at Modern Web Browser(part 4)[1]作者:Mariko Kosaka[2]译者:kyrieliu终于到最后一篇了!作为这个系列的...

    2024-01-30 21:36:05
  • MySQL触发器

    触发器含义在发生insert,update,delete等事件时,符合特定条件后,执行特定语句即为触发器。触发器操作创建触发器create trigger 触发器名称 begin或者after 触发事件 on 表名 for each row 执行语句;create trigger 触发器名称 begin或者after 触发事件 on 表名 for each row begi

    2024-01-30 21:35:59
  • SparkSQL项目

    SparkSQL项目

    YARN产生背景MapReduce1.X的问题:JobTracker的压力太大了;YARN的产生YARN的架构1个RM(ResourceManager)+N个(NodeManager)Resource...

    2024-01-30 21:35:30
  • 基于element-ui的table实现树级表格操作及单元格合并

    基于element-ui的table实现树级表格操作及单元格合并

    基于element-ui的table,在一张表内实现多级树状数据展示及同属性的单元格合并,并在表格内实现增删改操作。

    2024-01-30 21:35:21
  • 差分算法(用python语言实现)

    差分算法,易上手

    2024-01-30 21:35:14
  • 《美图数据统计分析平台架构演进》阅读有感

    《美图数据统计分析平台架构演进》阅读有感

    《美图数据统计分析平台架构演进》阅读有感数据统计是一个比较尴尬的事情,第一个它可能不是一个非常有技术含量的事情,对于技术人员的成长来说不是非常好。第二它可能是一个比较重复工作的事,需要解决一些简单的需求的重复工作。统计业务与技术碰撞这基本上是我自己亲身的经历,刚开始一个人做这一块的业务,会碰到一些有意思的点,可能分三个阶段,第一个阶段是在项目的初期,我们是怎么样去应对一些产品的初期需求...

    2024-01-30 21:34:45
  • unity 3.6在import package时只有custom package

    unity 3.6在import package时只有custom package

    【问题描述】下载的unity 3.6在import package时只有custom package没有其他包文件【解决方案】在asset store里搜索Standard Assets选择导入即可导入完成后在左下角的project assets中多了一个Standard Assets文件夹打开即可使用...

    2024-01-30 21:34:37
  • LLCC68寄存器模式开发-几个关键操作说明

    LLCC68寄存器模式开发-几个关键操作说明

    llcc68 lora模式寄存器说明

    2024-01-30 21:34:29