React 組件效能最佳化探索實踐

來源:互聯網
上載者:User

標籤:對象   cte   awk   實踐   產生   個人   blank   import   highlight   

轉自:http://www.tuicool.com/articles/Ar6Zruq

React本身就非常關注效能,其提供的虛擬DOM搭配上Diff演算法,實現對DOM操作最小粒度的改變也是非常的高效。然而其組件渲染機制,也決定了在對組件進行更新時還可以進行更細緻的最佳化。

react組件渲染

react的組件渲染分為初始化渲染和更新渲染。

在初始化渲染的時候會調用根組件下的所有組件的render方法進行渲染,如(綠色表示已渲染,這一層是沒有問題的):

但是當我們要更新某個子組件的時候,如的綠色組件(從根組件傳遞下來應用在綠色組件上的資料發生改變):

我們的理想狀態是只調用關鍵路徑上組件的render,如:

但是react的預設做法是調用所有組件的render,再對產生的虛擬DOM進行對比,如不變則不進行更新。這樣的render和虛擬DOM的對比明顯是在浪費,如(黃色表示浪費的render和虛擬DOM對比)

那麼如何避免發生這個浪費問題呢,這就要牽出我們的 shouldComponentUpdate

shouldComponentUpdate

react在每個組件生命週期更新的時候都會調用一個 shouldComponentUpdate(nextProps, nextState) 函數。它的職責就是返回true或false,true表示需要更新,false表示不需要,預設返回為true,即便你沒有顯示地定義 shouldComponentUpdate 函數。這就不難解釋上面發生的資源浪費了。

為了進一步說明問題,我們再引用一張官網的圖來解釋,如( SCU表示shouldComponentUpdate,綠色表示返回true(需要更新),紅色表示返回false(不需要更新);vDOMEq表示虛擬DOM比對,綠色表示一致(不需要更新),紅色表示發生改變(需要更新)):

根據渲染流程,首先會判斷shouldComponentUpdate(SCU)是否需要更新。如果需要更新,則調用組件的render產生新的虛擬DOM,然後再與舊的虛擬DOM對比(vDOMEq),如果對比一致就不更新,如果對比不同,則根據最小粒度改變去更新DOM;如果SCU不需要更新,則直接保持不變,同時其子項目也保持不變。

C1根節點,綠色SCU (true),表示需要更新,然後vDOMEq紅色,表示虛擬DOM不一致,需要更新。

C2節點,紅色SCU (false),表示不需要更新,所以C4,C5均不再進行檢查

C3節點同C1,需要更新

C6節點,綠色SCU (true),表示需要更新,然後vDOMEq紅色,表示虛擬DOM不一致,更新DOM。

C7節點同C2

C8節點,綠色SCU (true),表示需要更新,然後vDOMEq綠色,表示虛擬DOM一致,不更新DOM。

為了避免一定程度的浪費,react官方還在0.14版本中加入了無狀態組件,如下:

// es5function HelloMessage(props) {     return <div>Hello {props.name}</div>;}

  

// es6const HelloMessage = (props) => <div>Hello {props.name}</div>;

  

具體可參考官網: Reusable Components

既然明白了這關鍵所在,現在是時候向我們的大大小小一籮筐組件開刀了。

牛刀小試,直接把一些不需要更新的組件返回false

下面我們以音量表徵圖為例,這是一個svg表徵圖,不需要更新,所以直接return false

import React, {Component} from ‘react‘;class Mic extends Component {    constructor(props) {              super(props);    }    shouldComponentUpdate() {                  return false;    }    render() {        return (            <svg className="icon-svg icon-mic" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" aria-labelledby="title">                <title>mic</title>                <path className="path1" d="M15 22c2.761 0 5-2.239 5-5v-12c0-2.761-2.239-5-5-5s-5 2.239-5 5v12c0 2.761 2.239 5 5 5zM22 14v3c0 3.866-3.134 7-7 7s-7-3.134-7-7v-3h-2v3c0 4.632 3.5 8.447 8 8.944v4.056h-4v2h10v-2h-4v-4.056c4.5-0.497 8-4.312 8-8.944v-3h-2z"></path>            </svg>        )    }}export default Mic;    

  

登堂入室,對資料進行對比確定是否需要更新

先來個官網的例子,通過判斷id是否改變來確定是否需要更新:

shouldComponentUpdate: function(nextProps, nextState) {      return nextProps.id !== this.props.id;}

  看起來也沒那麼玄乎,直接一個 !== 對比下就ok了,那是不是所有的都可以這樣直接對比就可以呢? 我們先來看下js的兩個資料類型(原始類型與參考型別)的各自比較

// 原始類型var a = ‘hello the‘;var b = a;b = b + ‘world‘;console.log(a === b);  // false// 參考型別var c = [‘hello‘, ‘the‘];var d = c;d.push(‘world‘);console.log(c === d); // true

  

我們可以看到a和b不等,但是c和d是一樣一樣的,這修改了d,也直接修改了c,那還怎麼對比(關於原始類型與參考型別的區別這裡就不說明了)。

現在看來我們得分情況處理了,原始類型資料和參考型別資料得採用不同的辦法處理。

原始類型資料

這沒什麼好說的,直接比對就是了。但是每個人都是想偷懶的,這要是每個組件都要這樣去寫下也挺麻煩的,於是react官方有了外掛程式幫我們搞定這事:

PureRenderMixin (es5的外掛程式)

var PureRenderMixin = require(‘react-addons-pure-render-mixin‘);React.createClass({  mixins: [PureRenderMixin],  render: function() {           return <div className={this.props.className}>foo</div>;  }});

  Shallow Compare (es6的外掛程式)

var shallowCompare = require(‘react-addons-shallow-compare‘);export class SampleComponent extends React.Component {  shouldComponentUpdate(nextProps, nextState) {           return shallowCompare(this, nextProps, nextState);  }  render() {           return <div className={this.props.className}>foo</div>;  }} 

  

參考型別資料

既然參考型別資料一直返回true,那就得想辦法處理,能不能把前後的資料變成不一樣的引用呢,那樣不就不相等了嗎?於是就有了我們的不可變資料。

react官方提供了一個 Immutability Helpers

 

const newValue = {    ...oldValue    // 在這裡做你想要的修改};// 快速檢查 —— 只要檢查引用newValue === oldValue; // false// 如果你願意也可以用 Object.assign 文法const newValue2 = Object.assign({}, oldValue);newValue2 === oldValue; // false

然後在 shouldComponentUpdate 中進行比對

shouldComponentUpdate(nextProps) {    

  return isObjectEqual(this.props, nextProps);}

我們目前採用的是在reducer裡面更新資料使用 Object.assign({}, state, {newkey: newValue} (資料管理採用redux),然後在組件裡面根據某個具體的欄位判斷是否更新,如title或id等,而不是判斷整個對象:
shouldComponentUpdate: function(nextProps, nextState){         return nextProps.title !== this.props.title;}

  

 

React 組件效能最佳化探索實踐

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.