React高階元件替代Mixins

Samon發表於2016-08-26

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
    }

相關文章