上一篇文章的結尾
http://imweb.io/topic/5985cc4...
咱們說到,也許,不是全部的節點都須要從新渲染,對於那些不須要渲染的節點,咱們如何找到它們並作優化呢?html
本篇文章來具體解答這個問題。react
首先,先看這個應用:頁面的兩部分分別渲染5000個節點,從1-5000。當點擊按鈕以後,第二部分的節點會更新,從新渲染從2-5001的數字,可是第一部分保持不變。git
import React, { createElement, Component } from 'react'; import {render} from 'react-dom'; import Perf from 'react-addons-perf'; import ListItem from './ListItem' function arrayGenerator(length) { return Array.apply(null, { length: length }).map(Number.call, Number) } class App extends Component { constructor(props) { super(props) this.state = { multiplier: 1 } } resetMultiplier() { this.setState({ multiplier: 2 }) } render() { return ( <div className="App"> <button onClick={this.resetMultiplier.bind(this)}>Click Me</button> <ul> { arrayGenerator(5000).map(i => { return <ListItem key={i} text={i}/> }) } { arrayGenerator(5000).map(i => { return <ListItem key={i} text={i + this.state.multiplier}/> }) } </ul> </div> ); } } render(<App />,document.getElementById('main'));
gitbug 連接:
https://github.com/hhhuangqio...github
感興趣的同窗能夠下載跑一跑代碼web
這裏用react的Perf工具來測量從新渲染的時間。npm
使用方法:redux
npm install --save-dev react-addons-perf import Perf from 'react-addons-perf'
這裏主要用到四個方法:數組
Perf.start():開始計時app
Perf.stop():結束計時less
Perf.printInclusive():打印組件總的渲染時間
Perf.printWasted():打印浪費的時間
當咱們點擊按鈕,能夠看到控制檯打印出下面的信息:
由控制檯的數據能夠看出,App用了90.59ms渲染,其中渲染ListItem的時間爲55ms,渲染了10000次,其中有5000次是浪費的,由於這部分頁面的內容徹底沒有更新的改動。
既然是不須要渲染,那就要阻止它的渲染。React給咱們提供了一個方法shouldComponentUpdate(),當這個方法返回true的時候,須要從新渲染,false的時候不須要(默認是true).
在這個栗子中,只要text的值不變,就不須要從新渲染。因此,能夠這樣改寫ListItem 的shouldComponentUpdate
import React, { Component } from 'react' export default class ListItem extends Component { shouldComponentUpdate(nextProps, nextState) { return nextProps.text !== this.props.text } render() { let { text } = this.props return <li>{text}</li> } }
在從新點擊一下按鈕,在控制檯能夠發現
App總的渲染時間降到了62.14ms,而且ListItem只從新渲染了5000個節點,徹底消除了浪費的渲染。
對於上面的寫法,React提供了一個新的組件PureComponent來作這件事,它會自動淺對比props/state,當二者相同的時候不渲染節點。因此,listItem又能夠改寫成
import React, { PureComponent } from 'react' export default class ListItem extends PureComponent { render() { let { text } = this.props return <li>{text}</li> } }
跑一跑代碼
經過控制檯能夠看到達到的效果是同樣的(有點偏差是正常的)。
這裏再安利一個能夠發現應用裏是否存在不應從新渲染的節點工具:why-did-you-update
一、npm i --save-dev why-did-you-update 二、 import React from 'react' if (process.env.NODE_ENV !== 'production') { const {whyDidYouUpdate} = require('why-did-you-update') whyDidYouUpdate(React) }
而後點擊按鈕看控制檯
能夠看到Value did not change. Avoidable re-render!的警告,是否是很實用!
PureComponent只會淺比較,因此不適合用於深層嵌套的對象。同時,PureComponent不只僅會跳過本身的從新渲染,還會跳過它全部子節點的,因此要注意,用它的時候是最好沒有子節點而且不依賴於global state的展現型組件。
不知道有沒有人跟我有這樣的疑問,無狀態組件跟純淨組件有什麼不一樣?這裏作一個區分:
無狀態組件只是做爲一個展現組件,它的好處是:
易複用,易測試
與邏輯處理數據解耦,通常來講,app裏有越多無狀態組件越好,這說明邏輯處理都在上層,例如redux 中處理,這樣能夠在不渲染的前提下,測數據邏輯。
壞處:
沒有生命週期,沒辦法用shouldComponentUpdate阻止從新渲染,這也就是說,它沒有幫助咱們提升性能的做用,這也是它跟PureComponent最大的不一樣。
關於如何在實際中使用這兩個組件,還要根據具體的實際狀況來選擇~
綜上能夠看出,減小沒必要要的從新渲染對於提高咱們的性能有很大的意義。我我的以爲,在實際中,用Perf跟why-did-you-update兩個工具已經能夠很好幫咱們判斷哪部分不須要從新渲染,幫助咱們作出優化。
PureComponent那麼好用,可是使用PureComponent是有條件的呀~
因爲PureComponent只是作了一個淺比較,因此深層嵌套的對象跟數組都是比不出來的,可能會致使須要渲染的地方沒有從新渲染的錯誤展現。
那麼淺比較又是什麼呢?下篇文章咱們來繼續探索
參考連接: