react shouldComponentUpdate

對(duì)比vue艳狐,性能優(yōu)化對(duì)react更加重要途戒,shouldComponentUpdate又是react中性能重要的一個(gè)特性。

shouldComponentUpdatereact的一個(gè)生命周期僵驰,顧名思義喷斋,就是用于設(shè)置是否進(jìn)行組件更新

后面都使用SCU縮寫指代shouldComponentUpdate

SCU的基本使用

說到性能優(yōu)化之前唁毒,我們要先說一下SCU的用法:

  • 它有兩個(gè)參數(shù):
    • nextProps:更新后的props屬性
    • nextState:更新后的state狀態(tài)
  • 這個(gè)生命周期中,如果返回true代表會(huì)觸發(fā)重新渲染星爪,為false則不會(huì)浆西;默認(rèn)是返回true
  • 在這個(gè)生命周期中,我們可以根據(jù)某個(gè)狀態(tài)顽腾,來手動(dòng)設(shè)置是否觸發(fā)重新渲染

下面這個(gè)例子中近零,設(shè)置只有計(jì)數(shù)count狀態(tài)改變時(shí),才觸發(fā)渲染抄肖,否則則不渲染

import React, {Component} from 'react'

class SCU extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0,
      name: '小花'
    }
  }
  // 是否進(jìn)行更新的生命周期久信,它有兩個(gè)參數(shù),它允許我們自定義是否更新漓摩,默認(rèn)返回true
  // nextProps:更新后的props屬性
  // nextState: 更新后的state狀態(tài)
  shouldComponentUpdate(nextProps, nextState) {
    // 現(xiàn)在設(shè)置只有count改變時(shí)裙士,才觸發(fā)重新渲染
    if(nextState.count === this.state.count) {
      return false;
    }
    return true;
  }
  render() {
    const { count, name } = this.state
    // 第二個(gè)為要放至的dom元素位置
    return <div>
      <p>count: {count}</p>
      <p>name: {name}</p>
      <button onClick={this.changeCount}>累加count</button>
      <button onClick = {this.changeName}>不改變count,改變其它state狀態(tài)</button>
    </div>
  }
  changeCount = () => {
    this.setState({count: this.state.count + 1})
  }
  changeName = () => {
    this.setState({name: '小小'})
    console.log(this.state.name)
  }

}
export default SCU

當(dāng)改變this.state.name時(shí)管毙,因?yàn)樵?code>SCU做了判斷腿椎,沒改變到count的,雖然name變了夭咬,但不會(huì)觸發(fā)視圖更新

scu

當(dāng)改變count時(shí)啃炸,就發(fā)現(xiàn)視圖更新了,說明 scu中的設(shè)置生效了
image.png

什么時(shí)候用SCU?

reactSCU中是默認(rèn)返回true的卓舵,也就是說南用,只要父組件更新,那么所有的子組件都會(huì)無條件跟著更新掏湾,即使這個(gè)子組件內(nèi)容沒有任何更新裹虫。

但在日常開發(fā)中,我們常常是只需要更新其中一個(gè)或幾個(gè)子組件忘巧,其它未有任何改變的子組件恒界,我們并不希望它重新渲染,這時(shí)候就要會(huì)用到SCU來優(yōu)化砚嘴。

下面以一個(gè)例子說明:
Todolist 清單十酣,它有三個(gè)子組件:

  • TodoInput:輸入框,和提交按鈕
  • List:todolist际长,列表顯示組件
  • Footer:一些其它的描述信息
// TodoList.js
import React, { Component } from 'react';
import TodoInput from './TodoInput'
import List from './List'
import Footer from './Footer'

export default class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [
        {id: 0, title: '吃飯'},
        {id: 1, title: '睡覺'}
      ],
      footer: '頁尾信息'
    }
  }
  render() {
    return <div>
      <TodoInput updateList={this.updateList} />
      <List list={this.state.list}/>
      <hr/>
      <Footer footer={this.state.footer}/>
    </div>
  }
  updateList = (val) => {
    this.setState({
      list: this.state.list.concat({
        id: this.state.list.length,
        title: val
      })
    })
  }
}
// TodoInput.js
import React, { Component } from 'react';

export default class TodoInput extends Component {
  constructor(props) {
    super(props)
    this.state = {
      inputValue: ''
    }
  }
  render() {
    const { inputValue } = this.state
    return <div>
      <input type="text" value={inputValue} onChange={(e) => this.changeInput(e)} />
      <button onClick={() => this.props.updateList(this.state.inputValue)}>新增</button>
    </div>
  }
  changeInput = (e) => {
    this.setState({
      inputValue: e.target.value
    })
  }
}
// List.js  列表組件
export default function List(props) {
  return <div>
    {props.list.map(item => {
      return <p key={item.id}>{item.title}</p>
    })}
  </div>
}

// Footer.js
import React, { Component } from 'react';

export default class Footer extends Component {
  componentDidUpdate() {
    console.log('Footer組件更新');
  }
  render() {
    return <p>{this.props.footer}</p>
  }
}

當(dāng)新增一項(xiàng)事項(xiàng)時(shí)耸采,發(fā)現(xiàn)Footer組件即使沒更新內(nèi)容,也被重新渲染了

image.png

這其實(shí)就是一種性能的浪費(fèi)工育,因?yàn)楸旧硎菦]必要渲染的虾宇,只有Footer的內(nèi)容footer更新時(shí),我們才需要更新這個(gè)組件如绸,所以可以在SCU中優(yōu)化:

// Footer.js

shouldComponentUpdate(nextProps, nextState) {
     // 只有footer改變時(shí)嘱朽,才重新渲染
    if(nextProps.footer !== this.props.footer) {
      return true;
    }
    return false;
  }

此時(shí)旭贬,再去新增事項(xiàng)時(shí),就不會(huì)觸發(fā)Footer組件重新渲染了

image.png

SCU必須配合不可變值一起使用

這是因?yàn)槿绻皇褂貌豢勺冎禃r(shí)搪泳,那么對(duì)象的改變其實(shí)還是引用同一個(gè)地址稀轨,那么在SCU做對(duì)比時(shí),就不可避免要一次性遞歸比較里面所有的內(nèi)容:

  • 使用可變量來修改時(shí)
    SCU時(shí)岸军,要一次性遞歸遍歷對(duì)象的每一項(xiàng)才能準(zhǔn)確判斷出兩者是否相等奋刽,下面是使用lodash庫的isEqual方法來一次性遞歸遍歷,當(dāng)對(duì)象層級(jí)很深時(shí)艰赞,可想而知佣谐,是極其浪費(fèi)性能的
changeList = () => {
  // 使用可變量,SCU要付出極大代價(jià)方妖,不建議使用
    this.state.list.push({
      id: this.state.list.length,
      title: 'xxx'
    })
    this.setState({
      list: this.state.list
    })
}
    
shouldComponentUpdate(nextProps, nextState) {
    // _isEqual要深層遍歷每一項(xiàng)是否相等狭魂,才可以準(zhǔn)確判斷
    if(_.isEqual(nextState.list !== this.state.list) {
      return true;
    }
    return false;
  }
  • 使用不可變量來修改時(shí)
    使用不可變量來修改時(shí),因?yàn)樾聦?duì)象使用的是新的引用地址吁断,所以在SCU比對(duì)時(shí)趁蕊,只需要淺對(duì)比坞生,就可以判斷出兩者的不同
  updateList = () => {
    // 使用不可變量
    this.setState({
      list: this.state.list.concat({
        id: this.state.list.length,
        title: 'xxx'
      })
    })

  shouldComponentUpdate(nextProps, nextState) {

    // 使用不可變量時(shí)使用SCU
    if(nextState.list !== this.state.list) {
      return true;
    }
    return false;
  }

這也是為什么一直強(qiáng)調(diào)setState時(shí)要遵循react immutable不可變值理念的重要原因

react為什么不直接一開始就SCU優(yōu)化仔役,而是給用戶保留設(shè)置?

因?yàn)椴荒鼙WC用戶一定遵循immutable理念的寫法是己,如果用戶使用可變量來修改時(shí)又兵,reactSCU時(shí)就要付出極大性能,所以react并不選擇在一開始就在SCU優(yōu)化卒废,而是交給開發(fā)者自己選擇是否要使用SCU優(yōu)化

針對(duì)于使用了不可變值的組件沛厨,react其實(shí)提供了PureComponent實(shí)現(xiàn)SCU淺比較的優(yōu)化方案

SCU總結(jié)

  • SCU默認(rèn)返回true,即react默認(rèn)重新渲染所有子組件
  • 必須配合不可變值一起使用摔认,不然會(huì)有性能問題
  • SCU優(yōu)化并不一定在一開始就要使用逆皮,而是在遇到性能問題時(shí),我們才會(huì)考慮使用它
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末参袱,一起剝皮案震驚了整個(gè)濱河市电谣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抹蚀,老刑警劉巖剿牺,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異环壤,居然都是意外死亡晒来,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門郑现,熙熙樓的掌柜王于貴愁眉苦臉地迎上來湃崩,“玉大人荧降,你說我怎么就攤上這事≡芏粒” “怎么了誊抛?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長整陌。 經(jīng)常有香客問我拗窃,道長,這世上最難降的妖魔是什么泌辫? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任随夸,我火速辦了婚禮,結(jié)果婚禮上震放,老公的妹妹穿的比我還像新娘宾毒。我一直安慰自己,他們只是感情好殿遂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布诈铛。 她就那樣靜靜地躺著,像睡著了一般墨礁。 火紅的嫁衣襯著肌膚如雪幢竹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天恩静,我揣著相機(jī)與錄音焕毫,去河邊找鬼。 笑死驶乾,一個(gè)胖子當(dāng)著我的面吹牛邑飒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播级乐,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼疙咸,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了风科?” 一聲冷哼從身側(cè)響起撒轮,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丐重,沒想到半個(gè)月后腔召,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扮惦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年臀蛛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浊仆,死狀恐怖客峭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抡柿,我是刑警寧澤舔琅,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站洲劣,受9級(jí)特大地震影響备蚓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜囱稽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一郊尝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧战惊,春花似錦攘烛、人聲如沸媒熊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至各拷,卻和暖如春刁绒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撤逢。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工膛锭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粮坞,地道東北人蚊荣。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像莫杈,于是被迫代替她去往敵國和親互例。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 常見面試題:1.React組件如何通訊筝闹?2.JSX本質(zhì)是什么媳叨?3.context是什么?有何用途关顷?4.should...
    洛珎閱讀 709評(píng)論 0 2
  • 性能優(yōu)化 性能優(yōu)化糊秆,永遠(yuǎn)是面試的重點(diǎn),性能優(yōu)化對(duì)于 React 更加重要 在頁面中使用了setTimout()议双、a...
    Actoress閱讀 1,632評(píng)論 0 5
  • 基本使用 React基本使用 直接渲染 html痘番,相當(dāng)于 vue 中的 v-html React 事件 ...
    _1633_閱讀 460評(píng)論 0 1
  • React 和 Vue 有許多相似之處,它們都有: 使用 Virtual DOM 提供了響應(yīng)式 (Reactive...
    Nosaj閱讀 525評(píng)論 0 1
  • 在頁面中使用了setTimout()、addEventListener()等汞舱,要及時(shí)在componentWillU...
    漆鈺閱讀 292評(píng)論 0 0