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';
复制代码


相关文章
|
7月前
React-组件-TransitionGroup
React-组件-TransitionGroup
24 0
|
8天前
|
资源调度 前端开发 JavaScript
React组件
React组件
42 0
|
6月前
|
前端开发
使用react写一个简单的评论系统
使用react写一个简单的评论系统
|
7月前
|
前端开发 UED
React-组件-SwitchTransition
React-组件-SwitchTransition
68 0
|
7月前
|
前端开发 JavaScript
React-组件-TaggedTemplateLiterals
React-组件-TaggedTemplateLiterals
24 0
|
8月前
|
移动开发 前端开发 JavaScript
React | 认识React开发
React | 认识React开发
|
10月前
|
前端开发 JavaScript
react中怎么运用组件
react中怎么运用组件
|
11月前
|
设计模式 缓存 前端开发
|
12月前
|
前端开发 JavaScript
|
12月前
|
资源调度 前端开发

热门文章

最新文章