6

React高阶组件替代Mixins

minins将死,ES6的Class不对其进行支持,HOC就是解决办法。

那什么是高级组件?首先你得先了解请求ES6中的class只是语法糖,本质还是原型继承。能够更好的进行说明,我们将不会修改组件的代码。而是通过提供一些能够包裹组件组件, 并通过一些额外的功能来增强组件。这样的组件我们称之为高阶组件(Higher-Order Component)。

ES7中的新特性decorator(装饰器)就是使用高阶组件模式,transform-decorators-legacy是目前babel插件转换decorator的,可以研究下。下面看下如何实现React的PureRender功能(高阶组件和decorator一起讲解)。

PureRenderDecorator,decorator其实就是一个高阶组件。

import _ from 'lodash';

function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }

  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  const bHasOwnProperty = hasOwnProperty.bind(objB);
  for (let i = 0; i < keysA.length; i++) {
    const keyA = keysA[i];

    if (objA[keyA] === objB[keyA]) {
      continue;
    }

    // special diff with Array or Object
    if (_.isArray(objA[keyA])) {
      if (!_.isArray(objB[keyA]) || objA[keyA].length !== objB[keyA].length) {
        return false;
      } else if (!_.isEqual(objA[keyA], objB[keyA])) {
        return false;
      }
    } else if (_.isPlainObject(objA[keyA])) {
      if (!_.isPlainObject(objB[keyA]) || !_.isEqual(objA[keyA], objB[keyA])) {
        return false;
      }
    } else if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
      return false;
    }
  }

  return true;
}


function shallowCompare(instance, nextProps, nextState) {
  return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
}

function shouldComponentUpdate(nextProps, nextState) {
  return shallowCompare(this, nextProps, nextState);
}
/* eslint-disable no-param-reassign */
function pureRenderDecorator(component) {
  //覆盖了component中的shouldComponentUpdate方法
  component.prototype.shouldComponentUpdate = shouldComponentUpdate;
  return component;//Decorator不用返回,直接使用高阶组件需要return
}
/*****
*使用ES6 class 语法糖如下,decorator的没试过,decorator请使用上面的,不要return
*let pureRenderDecorator = component => class {
*  constructor(props) {
*    super(props);
*    component.prototype.shouldComponentUpdate = shouldComponentUpdate;
*  }
*  render(){
*    var Component = component;//自定义组件使用时要大写
*   return (
*        <Component {...this.props}/>
*    )
*  }
*}
******/
export { shallowEqual };
export default pureRenderDecorator;

如何使用?假设要使用的组件是Test

  • 直接使用

    import React from 'react';
    import { pureRenderDecorator } from "./pureRenderDecorator";
    
    class Test extends React.Component {
        // component code here
    }
    export default pureRenderDecorator(Test)

  • 通过decorator

    import React from 'react';
    import { pureRenderDecorator } from "./pureRenderDecorator";
    
    @pureRenderDecorator
    export default class Test extends React.Component {
        // component code here
    }

Samon
1.3k 声望92 粉丝