componentWillUpdate/componentDidUpdate什么時候會觸發(fā)?

基礎(chǔ)

React.Component

1.state更新或者父組件state更新都會觸發(fā)

React.PureComponent

1.state更新或者父組件傳遞過來的props有更新

React.PureComponent with Context

1.如果不注冊contextType亿卤,則與React.PureComponent一致涵但。
2.如果注冊了contextType,則與React.Component一致

如果在視圖中使用context value昭抒,當(dāng)context value有改變時栋豫,視圖會更新挤安,但不會觸發(fā)componentWillUpdate/componentDidUpdate

不注冊contextType

parent component

import React from 'react'

const MyContext = React.createContext({});

class Parent extends React.Component {
    state={
      num:1
    };

    add=()=>{
      let num = this.state.num;
      num+=1;
      this.setState({num:num})
    };

    render(){
        return (
            <MyContext.Provider value={this.state}>
              <div>
                  <div>{this.state.num}</div>
                  <button onClick={this.add}>+1s</button>
                  <Child />
              </div>
            </MyContext.Provider>
        )
    }
}

export default Parent

child component

class Child extends React.PureComponent {
    componentWillUpdate(nextProps, nextState, nextContext) {
        console.log('componentWillUpdate',nextProps, nextState, nextContext)
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('componentDidUpdate',prevProps, prevState, snapshot)
    }

    render(){
        return (
            <MyContext.Consumer>
                {(state)=>
                    <div>
                        I'm child component,
                        <p>
                            this num from parent :{state.num}
                        </p>
                    </div>
                }
            </MyContext.Consumer>
        )
    }
}

//如何注冊contextType
//Child.contextType = MyContext;

進(jìn)階

SCU shouldComponentUpdate

當(dāng)shouldComponentUpdate返回true時,React必須走到該節(jié)點并檢查它們丧鸯。
diff后發(fā)現(xiàn)元素不相等時蛤铜,React必須更新DOM,
當(dāng)diff沒有變化時丛肢,利用thunk機(jī)制可以使它不必更新DOM围肥。

但是PureComponent中,shouldComponentUpdate只是對stateprops的值進(jìn)行淺對比蜂怎,比如下方代碼:

class ListOfWords extends React.PureComponent {
    render() {
        return <div>{this.props.words.join(',')}</div>;
    }
}

export default class WordAdder extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            words: ['marklar'],
        };
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        // This section is bad style and causes a bug
        const words = this.state.words;
        words.push('marklar');
        this.setState({words: words});
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} />
                <ListOfWords words={this.state.words} />
            </div>
        );
    }
}

點擊button之后穆刻,ListOfWords組件并不會更新。

因此避免此問題的最簡單方法是避免你正在使用的stateprops值發(fā)生突變(mutating)杠步,而是比如這樣返回一個新值/新址:

- words.push('marklar');
- this.setState({words: words});
+ this.setState({words: words.concat('marklar')});
// 或者 ES6寫法
+ this.setState({words: [...words,'marklar']})

PS:這也是為什么React新版文檔內(nèi)變量全部換成const聲明了

優(yōu)化手動對比shouldComponentUpdate

1.有時組件需要選擇性更新氢伟,而不能完全依賴PureComponent榜轿,經(jīng)常會這么寫:

shouldComponentUpdate(nextPrpops) {
  return JSON.stringify(nextPrpops.data) !== JSON.stringify(this.props.data)
}

只有在this.props.data數(shù)據(jù)被改變時才更新,這樣寫在小數(shù)據(jù)場景下本身是沒有問題的朵锣,
但是如果在大數(shù)據(jù)的場景下可能會有問題谬盐,使用JSON.stringify暴力轉(zhuǎn)譯會非常耗時。


2.如果第一條的id不一樣就表示數(shù)據(jù)變化了行不行诚些,顯然在某種情況下是存在的飞傀,但不夠嚴(yán)謹(jǐn)。

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.data[0].id !== this.props.data[0].id
}



3.將data的比對轉(zhuǎn)換成current的比對

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.current !== this.props.current
}



4.給一個requestId跟蹤data诬烹,后面就只比對requestId砸烦。

this.setState({
  data,
  requestId: guid()
})

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.requestId !== this.props.requestId
}



上面的寫法可能都有問題,但主要想說的是寫代碼的時候可以想想是不是可以“將復(fù)雜的比對绞吁,變成簡單的比對

自定義shallowEqual函數(shù)

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 第一關(guān):基礎(chǔ)數(shù)據(jù)類型直接比較出結(jié)果
  if(is(objA, objB)) {
    return true
  }

  // 第二關(guān):只要有一個不是對象數(shù)據(jù)類型就返回false
  if(
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null ||
   ){
     return false
   }
  
  // 第三關(guān):如果兩個都是對象類型幢痘,比較兩者的屬性數(shù)量
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  if (keysA.length !== keysB.length) {
    return false;
  }

  // 第四關(guān):比較兩者的屬性是否相等,值是否相等
  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
+  }else {
+    if(!deepEqual(objA[keyA[i]], objB[keysA[i]])){
+      return false
+    }
  }

   // 默認(rèn)返回true
   return true
}

shallowEqual函數(shù)源代碼:react/package/shared/shallowEqual.js

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末家破,一起剝皮案震驚了整個濱河市雪隧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌员舵,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藕畔,死亡現(xiàn)場離奇詭異马僻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)注服,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門韭邓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溶弟,你說我怎么就攤上這事女淑。” “怎么了辜御?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵鸭你,是天一觀的道長。 經(jīng)常有香客問我擒权,道長袱巨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任碳抄,我火速辦了婚禮愉老,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剖效。我一直安慰自己嫉入,他們只是感情好焰盗,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著咒林,像睡著了一般熬拒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上映九,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天梦湘,我揣著相機(jī)與錄音,去河邊找鬼件甥。 笑死捌议,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的引有。 我是一名探鬼主播瓣颅,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼譬正!你這毒婦竟也來了宫补?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤曾我,失蹤者是張志新(化名)和其女友劉穎粉怕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抒巢,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡贫贝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛉谜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稚晚。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖型诚,靈堂內(nèi)的尸體忽然破棺而出客燕,到底是詐尸還是另有隱情,我是刑警寧澤狰贯,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布也搓,位于F島的核電站,受9級特大地震影響暮现,放射性物質(zhì)發(fā)生泄漏还绘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一栖袋、第九天 我趴在偏房一處隱蔽的房頂上張望拍顷。 院中可真熱鬧,春花似錦塘幅、人聲如沸昔案。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锥咸。三九已至,卻和暖如春录煤,著一層夾襖步出監(jiān)牢的瞬間捞稿,已是汗流浹背又谋。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留娱局,地道東北人彰亥。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像衰齐,于是被迫代替她去往敵國和親任斋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

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