React性能優化: 劍走偏鋒(二)

簡介

上一次, 咱們介紹了使用forceUpdate來重寫shouldComponent生命週期(React性能優化: 劍走偏鋒(一)). 這一次咱們繼續這個話題.javascript

react提供了一個PureComponent, 也是重寫了shouldComponentUpdate, 不過它作的是一個淺比較. 也就是說它能知足的場景很是有限. 若是項目中使用了immutable數據結構, 那麼改比較基本就是失效了.java

此次咱們也定義個組件XPureComponent組件, 重寫shouldComponentUpdate生命週期, 讓它可以知足更多的場景. 不限制state和props的數據結構. 能夠是任意的. 好比簡單對象, 複雜對象, immutable對象, HTMLELEMENT節點等任意對象.node

XPureComponent

import React from 'react';

import equals from './compare';

/** * @template Props * @template State * @template Snapshot * * @extends {React.Component<Props, State, Snapshot>} */
class XPureComponent extends React.Component {
  /** * @override */
  shouldComponentUpdate(nextProps, nextState) {
    // 按照先State再Props的順序比較,不一致則須要更新。
    return !(equals(this.state, nextState) && equals(this.props, nextProps));
  }
}

export default XPureComponent;

複製代碼

後面全部class組件就繼承這個XPureComponentreact

class XApp extends XPureComponent {
    render(){
        return <div></div>
    }
}
複製代碼

compare.js的實現

import { isImmutable, is } from 'immutable';
import { isEqual } from 'lodash';

const excludeKeys = ['__proto__', 'children'];

/** * 判斷是否爲dom節點對象 * @param node * @returns {boolean} */
const isDomNode = node => {
  return node && node.nodeName;
};

/** * 比較兩個大對象. * @param {Any} first * @param {Any} second */
const equals = (first, second) => {
  //判斷是否爲dom節點對象.
  if(isDomNode(first) && isDomNode(second)){
    return first.isSameNode(second);
  }

  // 先判斷是否爲同一個對象.
  if(first === second){
    return true;
  }

  // 兩個都是
  if (isImmutable(first) && isImmutable(second)) {
    return is(first, second);
  }

  // 只有一個是
  if (isImmutable(first) || isImmutable(second)) {
    return false;
  }

  // 兩個都是普通對象.
  // 比較第一層.
  if (
    first &&
    second &&
    typeof first === 'object' &&
    typeof second === 'object'
  ) {
    const firstKeys = Object.keys(first);
    const secondKeys = Object.keys(second);

    // 先比較長度
    if (firstKeys.length !== secondKeys.length) {
      return false;
    }

    // 再比較key.
    const equal = isEqual(firstKeys, secondKeys);
    if (!equal) {
      return false;
    }

    // key相同的狀況下.
    for (let i = 0; i < firstKeys.length; i++) {
      const key = firstKeys[i];
      const isExcluded = excludeKeys.findIndex(k => k === key) !== -1;

      // 遞歸比較.
      if (!isExcluded && !equals(first[key], second[key])) {
        return false;
      }
    }

    return true;
  }

  return isEqual(first, second);
};

export default equals;

複製代碼

經測試, 比較所花的時間是毫秒級別, 組件避免了大量的重複渲染. 性能提高很是明顯. 目前該方法已經運用到實際的項目中.

相關文章
相關標籤/搜索