摘要:如何修復(fù)既然是不需要渲染,那就要阻止它的渲染。我個(gè)人覺得,在實(shí)際中,用跟兩個(gè)工具已經(jīng)可以很好幫我們判斷哪部分不需要重新渲染,幫助我們做出優(yōu)化。
背景
上一篇文章的結(jié)尾
http://imweb.io/topic/5985cc4...
我們說到,也許,不是所有的節(jié)點(diǎn)都需要重新渲染,對(duì)于那些不需要渲染的節(jié)點(diǎn),我們?nèi)绾握业剿鼈儾⒆鰞?yōu)化呢?
本篇文章來具體解答這個(gè)問題。
應(yīng)用分析首先,先看這個(gè)應(yīng)用:頁面的兩部分分別渲染5000個(gè)節(jié)點(diǎn),從1-5000。當(dāng)點(diǎn)擊按鈕之后,第二部分的節(jié)點(diǎn)會(huì)更新,重新渲染從2-5001的數(shù)字,但是第一部分保持不變。
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 (); } } render({ arrayGenerator(5000).map(i => { return
}) } { arrayGenerator(5000).map(i => { return }) } ,document.getElementById("main"));
gitbug 鏈接:
https://github.com/hhhuangqio...
感興趣的同學(xué)可以下載跑一跑代碼
分析更新時(shí)間這里用react的Perf工具來測量重新渲染的時(shí)間。
使用方法:
npm install --save-dev react-addons-perf import Perf from "react-addons-perf"
這里主要用到四個(gè)方法:
Perf.start():開始計(jì)時(shí)
Perf.stop():結(jié)束計(jì)時(shí)
Perf.printInclusive():打印組件總的渲染時(shí)間
Perf.printWasted():打印浪費(fèi)的時(shí)間
當(dāng)我們點(diǎn)擊按鈕,可以看到控制臺(tái)打印出下面的信息:
由控制臺(tái)的數(shù)據(jù)可以看出,App用了90.59ms渲染,其中渲染ListItem的時(shí)間為55ms,渲染了10000次,其中有5000次是浪費(fèi)的,因?yàn)檫@部分頁面的內(nèi)容完全沒有更新的改動(dòng)。
如何修復(fù)既然是不需要渲染,那就要阻止它的渲染。React給我們提供了一個(gè)方法shouldComponentUpdate(),當(dāng)這個(gè)方法返回true的時(shí)候,需要重新渲染,false的時(shí)候不需要(默認(rèn)是true).
在這個(gè)栗子中,只要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
在重新點(diǎn)擊一下按鈕,在控制臺(tái)可以發(fā)現(xiàn)
App總的渲染時(shí)間降到了62.14ms,并且ListItem只重新渲染了5000個(gè)節(jié)點(diǎn),完全消除了浪費(fèi)的渲染。
對(duì)于上面的寫法,React提供了一個(gè)新的組件PureComponent來做這件事,它會(huì)自動(dòng)淺對(duì)比props/state,當(dāng)兩者相同的時(shí)候不渲染節(jié)點(diǎn)。所以,listItem又可以改寫成
import React, { PureComponent } from "react" export default class ListItem extends PureComponent { render() { let { text } = this.props return
跑一跑代碼
通過控制臺(tái)可以看到達(dá)到的效果是一樣的(有點(diǎn)誤差是正常的)。
這里再安利一個(gè)可以發(fā)現(xiàn)應(yīng)用里是否存在不該重新渲染的節(jié)點(diǎn)工具:why-did-you-update
使用方法1、npm i --save-dev why-did-you-update 2、 import React from "react" if (process.env.NODE_ENV !== "production") { const {whyDidYouUpdate} = require("why-did-you-update") whyDidYouUpdate(React) }
然后點(diǎn)擊按鈕看控制臺(tái)
可以看到Value did not change. Avoidable re-render!的警告,是不是很實(shí)用!
PureComponent只會(huì)淺比較,所以不適合用于深層嵌套的對(duì)象。同時(shí),PureComponent不僅僅會(huì)跳過自己的重新渲染,還會(huì)跳過它所有子節(jié)點(diǎn)的,所以要注意,用它的時(shí)候是最好沒有子節(jié)點(diǎn)并且不依賴于global state的展示型組件。
與Staleless的關(guān)系不知道有沒有人跟我有這樣的疑問,無狀態(tài)組件跟純凈組件有什么不同?這里做一個(gè)區(qū)分:
無狀態(tài)組件只是作為一個(gè)展示組件,它的好處是:
易復(fù)用,易測試
與邏輯處理數(shù)據(jù)解耦,一般來說,app里有越多無狀態(tài)組件越好,這說明邏輯處理都在上層,例如redux 中處理,這樣可以在不渲染的前提下,測數(shù)據(jù)邏輯。
壞處:
沒有生命周期,沒辦法用shouldComponentUpdate阻止重新渲染,這也就是說,它沒有幫助我們提高性能的作用,這也是它跟PureComponent最大的不同。
關(guān)于如何在實(shí)際中使用這兩個(gè)組件,還要根據(jù)具體的實(shí)際情況來選擇~
總結(jié)綜上可以看出,減少不必要的重新渲染對(duì)于提升我們的性能有很大的意義。我個(gè)人覺得,在實(shí)際中,用Perf跟why-did-you-update兩個(gè)工具已經(jīng)可以很好幫我們判斷哪部分不需要重新渲染,幫助我們做出優(yōu)化。
遺留點(diǎn)PureComponent那么好用,但是使用PureComponent是有條件的呀~
由于PureComponent只是做了一個(gè)淺比較,所以深層嵌套的對(duì)象跟數(shù)組都是比不出來的,可能會(huì)導(dǎo)致需要渲染的地方?jīng)]有重新渲染的錯(cuò)誤展示。
那么淺比較又是什么呢?下篇文章我們來繼續(xù)探索
參考鏈接:
1、https://60devs.com/pure-compo...
2、https://engineering.musefind....
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84777.html
摘要:事件系統(tǒng)合成事件的綁定方式合成事件的實(shí)現(xiàn)機(jī)制事件委派和自動(dòng)綁定。高階組件如果已經(jīng)理解高階函數(shù),那么理解高階組件也很容易的。例如我們常見的方法等都是高階函數(shù)。對(duì)測試群眾來說,從質(zhì)量保證的角度出發(fā),單元測試覆蓋率是 事件系統(tǒng) 合成事件的綁定方式 `Test` 合成事件的實(shí)現(xiàn)機(jī)制:事件委派和自動(dòng)綁定。 React合成事件系統(tǒng)的委托機(jī)制,在合成事件內(nèi)部僅僅是對(duì)最外層的容器進(jìn)行了綁定,并且依賴...
摘要:對(duì)此沒有任何限制,它不關(guān)心這個(gè)。一種控制變化的辦法是不可改變的,持久化的數(shù)據(jù)結(jié)構(gòu)。總結(jié)檢測變化時(shí)開發(fā)中的核心問題,而框架們以各種方式解決這個(gè)問題。因?yàn)榻M件內(nèi)的變化是不被允許的。 AngularJS:臟檢查 我不知道什么更新了,所以當(dāng)更新的時(shí)候,我只能檢查所有的東西。 AngularJS 類似于 Ember,當(dāng)狀態(tài)改變的時(shí)候,必須人工去處理。但不同的是,AngularJS 從不同的角度來...
摘要:原方式中是經(jīng)過壓縮的腳本文件,預(yù)編譯后則是二進(jìn)制文件。兩者影響疊加導(dǎo)致整體減小,包大小得到優(yōu)化。引擎包引擎包官方文檔中對(duì)內(nèi)存區(qū)的描述您的應(yīng)用用于處理代碼和資源如字節(jié)碼已優(yōu)化或已編譯的碼庫和字體的內(nèi)存。本文首發(fā)自普惠出行產(chǎn)品技術(shù) 自從 Google 的 Flutter 發(fā)布之后,F(xiàn)acebook 對(duì) React-Native 的迭代開始快了起來,優(yōu)化 React-Native 的性能表現(xiàn)...
摘要:表示調(diào)用棧在下一將要執(zhí)行的任務(wù)。兩方性能解藥我們一般有兩種方案突破上文提到的瓶頸將耗時(shí)高成本高易阻塞的長任務(wù)切片,分成子任務(wù),并異步執(zhí)行這樣一來,這些子任務(wù)會(huì)在不同的周期執(zhí)行,進(jìn)而主線程就可以在子任務(wù)間隙當(dāng)中執(zhí)行更新操作。 showImg(https://segmentfault.com/img/remote/1460000016008111); 性能一直以來是前端開發(fā)中非常重要的話題...
閱讀 3708·2021-09-22 15:28
閱讀 1329·2021-09-03 10:35
閱讀 903·2021-09-02 15:21
閱讀 3510·2019-08-30 15:53
閱讀 3520·2019-08-29 17:25
閱讀 596·2019-08-29 13:22
閱讀 1583·2019-08-28 18:15
閱讀 2309·2019-08-26 13:57