React-HOC了解一下

简介: 最近在公司接了一个老项目迁移React。在组件开发过程中,发现有一些组件的处理逻辑很类似。想在某一个地方来统一处理。进过思考和分析,发现HOC(higher-order component)很适合完成此类工作。 再次来总结HOC的概念和基本用法。

用技术改变生活,用生活完善技术。来自携程(旅悦)一枚向全栈方向努力奔跑的前端工程师。 微信同步:wDxKn89

最近在公司接了一个老项目迁移React。在组件开发过程中,发现有一些组件的处理逻辑很类似。想在某一个地方来统一处理。进过思考和分析,发现HOC(higher-order component)很适合完成此类工作。 再次来总结HOC的概念和基本用法。


HOC本质

针对React开发来讲,component是页面的基本组成单位。一个页面可以由很多拥有各自处理逻辑的组件来组合。正如在开发工程中遇到的问题,某几个组件拥有类似的数据过程,是不是可以采用某一种机制或者方法来统一处理该数据处理。

所以HOC就出现了。

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

注意:HOC是一个function而这个函数接受一个组件,return被处理过的组件。

const EnhancedComponent = higherOrderComponent(WrappedComponent);
复制代码

Code实现

案例重现

现在有一个需求,现在有TestTableA,TestTableB,他们用于渲染table数据,同时接收的数据格式也类似。只是TestTableA比TestTableB多一列展示数据。

col1 col2 col3
内容 内容 内容
内容 内容 内容


col1 col2
内容 内容
内容 内容

代码实现

现在采用HOC来统一处理table colum的拼装和数据的获取。(组件是用的Antd)

ReferencePriceFactory (HOC组件构建)

import React from 'react';
function ReferencePriceFactory(WrappedComponent,configInfo) {
  return class extends React.Component {
    constructor(props){
      super(props);
    }
    render() {
        //这里为了方便,直接假设用调用处将数据传入
      const {tableData} = this.props;
      renderContent
      const renderContent = (text, row, index) => {
        let value;
        const obj = {
          children: {},
          props: {}
        }
        value = <span>{text}</span>
        obj.children = value;
        return obj;
      }
      let Columns = [{
        title:'col1' ,
        dataIndex:'type',
        render: (text,record,index) =>renderContent(text,record,index)
      }, {
        title: 'col2',
        dataIndex:'referencePrice',
        render: (text,record,index) =>renderContent(text,record,index)
      }];
      let empty = {
        colSpan:0,
        render: (text, record, index) => {
          let value = null;
          const obj = {
            children: value,
            props: {},
          };
          obj.props.colSpan = 0;
          return obj;
        },
      };
      let  extraColumns =configInfo? {
        title: col3,
        dataIndex:'playPrice',
        render: (text,record,index) =>renderContent(text,record,index)
      }:empty;
      const finalColumns = [...Columns,extraColumns];
      return <WrappedComponent {...this.props} finalColumns={finalColumns}/>;
    }
  }
}
export default ReferencePriceFactory;
复制代码

TestTableA/TestTableB代码实现

import React from 'react';
import { Table} from 'antd';
export default class TestTableA extends React.Component {
  constructor(props, context) {
    super(props, context);
  }
  render() {
    let {finalColumns,tableData} = this.props;
    return (
      <span>
        <Table dataSource={tableData} columns={finalColumns} pagination={false} />
      </span>
    )
  }
}
复制代码

组件调用

const EnhancedTestTableA = ReferencePriceFactory(TestTableA,true);
const EnhancedTestTableB = ReferencePriceFactory(TestTableB,true);
export default class Test extends React.Component {
  constructor(props, context) {
    super(props, context);
  }
  render() {
    const {record} = this.props;
    return (
      <span>
        <EnhancedTestTableA record={record}/>
        <EnhancedTestTableB record={record}/>
      </span>
  )
  }
}
复制代码

在需要用到该组件的地方进行组件的处理,并调用。

HOC使用注意事项

不能修改原始组件

function logProps(InputComponent) {
//通过修改prototype来修改组件
  InputComponent.prototype.componentWillReceiveProps = function(nextProps) {
    console.log('Current props: ', this.props);
    console.log('Next props: ', nextProps);
  };
 //此处其实已经修改了InputComponent了
  return InputComponent;
}
// 组件调用
const EnhancedComponent = logProps(InputComponent);
复制代码

通过该方式来处理组件,最大的坏处就是如果还有另外一个HOC来对该组件进行加强(修改的是同一个方法),最后一次修改会对上一次加强的结果进行重写。

通过直接修改组件的方法,是弱抽象的。 如果想规避上述问题,构建一个HOC来加强组件是通过构建一个组件来调用需要被加强的组件。

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentWillReceiveProps(nextProps) {
      console.log('Current props: ', this.props);
      console.log('Next props: ', nextProps);
    }
    render() {
      return <WrappedComponent {...this.props} />;
    }
  }
}
复制代码

通过如上的分析会发现HOC和Container component处理方式很类似。

多个HOC组合使用

通过上文分析,HOC的本质就是一个用于返回被加强的组件的函数。所以如果一个组件需要进行不同维度的加强。就需要对组件进行多次HOC处理。

const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
复制代码

但是如果对函数式编程有了解的话,就会对compose有过了解。 通过compose处理上述代码可以改写如下:

const enhance = compose(
  withRouter,
  connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)
复制代码

Note

HOC是不能够在render方法中使用的。

React的diff算法通过判断component ID来决定是否更新存在的子树或者删除子树,并且重新加载一个新的。如果从render方法中返回的组件(===)原来的渲染的组件。但是HOC是一个函数,每次调用都会返回一个新的组件,所以render方法每次调用都会触发diff处理,并将原有的组件进行删除,重新加载一个新的组件。

组件的静态方法必须在HOC中重新调用

当你应用HOC通过调用原始组件通过加强来返回一个新的组件。这意味着新的组件没有原始组件的任何静态方法,所以想要在新的组件中使用静态方法的话,就需要在HOC中进行重新调用。

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}
复制代码

或者通过将静态方法export出来,在调用出import

MyComponent.someFunction = someFunction;
export default MyComponent;
//单独导出
export { someFunction };
import MyComponent, { someFunction } from './MyComponent.js';
复制代码


相关文章
|
6月前
|
存储 安全 Nacos
阿里云 MSE Nacos 发布全新“安全防护”模块,简化安全配置,提升数据保护
阿里云在其微服务引擎(MSE)注册配置中心 Nacos 上正式推出全新“安全防护”功能模块,旨在帮助企业用户有效管理安全状态和降低开启安全相关功能的学习成本,提升微服务架构的安全性。
247 25
|
安全 Java 网络安全
构建一个安全的电子商务平台
【8月更文挑战第13天】构建一个安全的电子商务平台需要从多个方面入手,包括选用安全的开发语言和框架、强化数据加密与认证机制、构建安全的支付系统、加强服务器与网络安全、遵循安全标准和法规、定期进行安全审计与培训以及建立应急响应与灾难恢复机制等。只有全面考虑并落实这些最佳实践,才能确保电子商务平台的安全性和可靠性。
|
存储 关系型数据库 MySQL
XtraBackup 的版本大揭秘:突破迷雾,揭开其支持 MySQL 版本的震撼真相,捍卫数据安全!
【8月更文挑战第7天】XtraBackup 是 MySQL 备份领域的热门工具,适用于多个版本。它为 MySQL 8.0 提供高效备份,确保数据安全。同样支持 MySQL 5.7 和其他稳定版如 5.6,精确备份各类数据结构。
278 0
|
SQL Java 关系型数据库
IDEA+Java+JSP+Mysql+Tomcat实现Web商品信息管理系统
IDEA+Java+JSP+Mysql+Tomcat实现Web商品信息管理系统
764 0
IDEA+Java+JSP+Mysql+Tomcat实现Web商品信息管理系统
|
SQL 关系型数据库 数据库
【MySQL】:DDL数据库定义与操作
【MySQL】:DDL数据库定义与操作
656 0
|
Java
java包装器类型
java包装器类型
155 0
|
关系型数据库 MySQL API
MariaDB数据库中如何允许远程链接mysql并开放3306端口
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可。开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方式来避开这个风险。
1395 0
|
架构师 JavaScript Java
【java】——OA初了解
现在几乎每写一篇博文,小编都想说一下大的背景,来思考一下基于怎样的一个背景下我有了这篇博文O(∩_∩)O~
遍历HashMap的四种方式
遍历HashMap的四种方式
190 0
|
SQL Java 数据库连接
跟我一起学mybatis之注解开发多表操作
跟我一起学mybatis之注解开发多表操作
198 0
跟我一起学mybatis之注解开发多表操作