React 新版本生命周期函數(shù)變動

????????React 官方正式發(fā)布了 v16.3 版本柑营。在這次的更新中陆淀,除了前段時(shí)間被熱烈討論的新 Context API之外慢味,新引入的兩個(gè)生命周期函數(shù)getDerivedStateFromProps璧诵,getSnapshotBeforeUpdate以及在未來 v17.0 版本中即將被移除的三個(gè)生命周期函數(shù)componentWillMount轴猎,componentWillReceiveProps莉钙,componentWillUpdate也非常值得我們花點(diǎn)時(shí)間去探究一下其背后的原因以及在具體項(xiàng)目中的升級方案廓脆。

componentWillMount


首屏無數(shù)據(jù)導(dǎo)致白屏

????????在 React 應(yīng)用中,許多開發(fā)者為了避免第一次渲染時(shí)頁面因?yàn)闆]有獲取到異步數(shù)據(jù)導(dǎo)致的白屏磁玉,而將數(shù)據(jù)請求部分的代碼放在了componentWillMount中停忿,希望可以避免白屏并提早異步請求的發(fā)送時(shí)間。但事實(shí)上在componentWillMount執(zhí)行后蚊伞,第一次渲染就已經(jīng)開始了席赂,所以如果在componentWillMount執(zhí)行時(shí)還沒有獲取到異步數(shù)據(jù)的話,頁面首次渲染時(shí)也仍然會處于沒有異步數(shù)據(jù)的狀態(tài)时迫。換句話說颅停,組件在首次渲染時(shí)總是會處于沒有異步數(shù)據(jù)的狀態(tài),所以不論在哪里發(fā)送數(shù)據(jù)請求掠拳,都無法直接解決這一問題癞揉。而關(guān)于提早發(fā)送數(shù)據(jù)請求,官方也鼓勵(lì)將數(shù)據(jù)請求部分的代碼放在組件的constructor中,而不是componentWillMount烧董。

????????另一個(gè)常見的componentWillMount的用例是在服務(wù)端渲染時(shí)獲取數(shù)據(jù)毁靶,因?yàn)樵诜?wù)端渲染時(shí)componentDidMount是不會被調(diào)用的。針對這個(gè)問題逊移,筆者這里提供兩種解法预吆。第一個(gè)簡單的解法是將所有的數(shù)據(jù)請求都放在componentDidMount中,即只在客戶端請求異步數(shù)據(jù)胳泉。這樣做可以避免在服務(wù)端和客戶端分別請求兩次相同的數(shù)據(jù)(componentWillMount在客戶端渲染時(shí)同樣會被調(diào)用到)拐叉,但很明顯的缺點(diǎn)就是無法在服務(wù)端渲染時(shí)獲取到頁面渲染所需的所有數(shù)據(jù),所以如果我們需要保證服務(wù)端返回的 HTML 就是用戶最終看到的 HTML 的話扇商,我們可以將每個(gè)頁面的數(shù)據(jù)獲取邏輯單獨(dú)抽離出來凤瘦,然后一一對應(yīng)到相應(yīng)的頁面,在服務(wù)端根據(jù)當(dāng)前頁面的路由找到相應(yīng)的數(shù)據(jù)請求案铺,利用鏈?zhǔn)降?Promise 在渲染最終的頁面前就將數(shù)據(jù)塞入 redux store 或其他數(shù)據(jù)管理工具中蔬芥,這樣服務(wù)端返回的 HTML 就是包含異步數(shù)據(jù)的結(jié)果了。

事件訂閱

????????另一個(gè)常見的用例是在componentWillMount中訂閱事件控汉,并在componentWillUnmount中取消掉相應(yīng)的事件訂閱笔诵。但事實(shí)上 React 并不能夠保證在componentWillMount被調(diào)用后,同一組件的componentWillUnmount也一定會被調(diào)用姑子。一個(gè)當(dāng)前版本的例子如服務(wù)端渲染時(shí)乎婿,componentWillUnmount是不會在服務(wù)端被調(diào)用的,所以在componentWillMount中訂閱事件就會直接導(dǎo)致服務(wù)端的內(nèi)存泄漏街佑。另一方面谢翎,在未來 React 開啟異步渲染模式后,在componentWillMount被調(diào)用之后沐旨,組件的渲染也很有可能會被其他的事務(wù)所打斷森逮,導(dǎo)致componentWillUnmount不會被調(diào)用。而componentDidMount就不存在這個(gè)問題希俩,在componentDidMount被調(diào)用后吊宋,componentWillUnmount一定會隨后被調(diào)用到,并根據(jù)具體代碼清除掉組件中存在的事件訂閱颜武。

升級方案

????????將現(xiàn)有?componentWillMount?中的代碼遷移至?componentDidMount?即可。


componentWillReceiveProps


更新由 props 決定的 state 及處理特定情況下的回調(diào)

????????在老版本的 React 中拖吼,如果組件自身的某個(gè) state 跟其 props 密切相關(guān)的話鳞上,一直都沒有一種很優(yōu)雅的處理方式去更新 state,而是需要在componentWillReceiveProps中判斷前后兩個(gè) props 是否相同吊档,如果不同再將新的 props 更新到相應(yīng)的 state 上去篙议。這樣做一來會破壞 state 數(shù)據(jù)的單一數(shù)據(jù)源,導(dǎo)致組件狀態(tài)變得不可預(yù)測,另一方面也會增加組件的重繪次數(shù)鬼贱。類似的業(yè)務(wù)需求也有很多移怯,如一個(gè)可以橫向滑動的列表,當(dāng)前高亮的 Tab 顯然隸屬于列表自身的狀態(tài)这难,但很多情況下舟误,業(yè)務(wù)需求會要求從外部跳轉(zhuǎn)至列表時(shí),根據(jù)傳入的某個(gè)值姻乓,直接定位到某個(gè) Tab嵌溢。

????????在新版本中,React 官方提供了一個(gè)更為簡潔的生命周期函數(shù):

? ??????????????????static getDerivedStateFromProps(nextProps, prevState)

?????????通常來講蹋岩,在componentWillReceiveProps中赖草,我們一般會做以下兩件事,一是根據(jù) props 來更新 state剪个,二是觸發(fā)一些回調(diào)秧骑,如動畫或頁面跳轉(zhuǎn)等。在老版本的 React 中扣囊,這兩件事我們都需要在componentWillReceiveProps中去做腿堤。而在新版本中,官方將更新 state 與觸發(fā)回調(diào)重新分配到了getDerivedStateFromProps與componentDidUpdate中如暖,使得組件整體的更新邏輯更為清晰笆檀。而且在getDerivedStateFromProps中還禁止了組件去訪問 this.props,強(qiáng)制讓開發(fā)者去比較 nextProps 與 prevState 中的值盒至,以確保當(dāng)開發(fā)者用到getDerivedStateFromProps這個(gè)生命周期函數(shù)時(shí)酗洒,就是在根據(jù)當(dāng)前的 props 來更新組件的 state,而不是去做其他一些讓組件自身狀態(tài)變得更加不可預(yù)測的事情枷遂。

升級方案

????????將現(xiàn)有componentWillReceiveProps中的代碼根據(jù)更新 state 或回調(diào)樱衷,分別在getDerivedStateFromProps及componentDidUpdate中進(jìn)行相應(yīng)的重寫即可,注意新老生命周期函數(shù)中prevProps酒唉,this.props矩桂,nextProps,prevState痪伦,this.state的不同侄榴。


componentWillUpdate


處理因?yàn)?props 改變而帶來的副作用

????????與componentWillReceiveProps類似,許多開發(fā)者也會在componentWillUpdate中根據(jù) props 的變化去觸發(fā)一些回調(diào)网沾。但不論是componentWillReceiveProps還是componentWillUpdate癞蚕,都有可能在一次更新中被調(diào)用多次,也就是說寫在這里的回調(diào)函數(shù)也有可能會被調(diào)用多次辉哥,這顯然是不可取的桦山。與componentDidMount類似攒射,componentDidUpdate也不存在這樣的問題,一次更新中componentDidUpdate只會被調(diào)用一次恒水,所以將原先寫在componentWillUpdate中的回調(diào)遷移至componentDidUpdate就可以解決這個(gè)問題会放。

在組件更新前讀取 DOM 元素狀態(tài)

????????另一個(gè)常見的componentWillUpdate的用例是在組件更新前,讀取當(dāng)前某個(gè) DOM 元素的狀態(tài)钉凌,并在componentDidUpdate中進(jìn)行相應(yīng)的處理咧最。但在 React 開啟異步渲染模式后,render 階段和 commit 階段之間并不是無縫銜接的甩骏,也就是說在 render 階段讀取到的 DOM 元素狀態(tài)并不總是和 commit 階段相同窗市,這就導(dǎo)致在componentDidUpdate中使用componentWillUpdate中讀取到的 DOM 元素狀態(tài)是不安全的,因?yàn)檫@時(shí)的值很有可能已經(jīng)失效了饮笛。

????????為了解決上面提到的這個(gè)問題咨察,React 提供了一個(gè)新的生命周期函數(shù):

? ??????????????getSnapshotBeforeUpdate(prevProps, prevState)

????????與componentWillUpdate不同,getSnapshotBeforeUpdate會在最終的 render 之前被調(diào)用福青,也就是說在getSnapshotBeforeUpdate中讀取到的 DOM 元素狀態(tài)是可以保證與componentDidUpdate中一致的摄狱。雖然getSnapshotBeforeUpdate不是一個(gè)靜態(tài)方法,但我們也應(yīng)該盡量使用它去返回一個(gè)值无午。這個(gè)值會隨后被傳入到componentDidUpdate中媒役,然后我們就可以在componentDidUpdate中去更新組件的狀態(tài),而不是在getSnapshotBeforeUpdate中直接更新組件狀態(tài)宪迟。

升級方案

????????將現(xiàn)有的componentWillUpdate中的回調(diào)函數(shù)遷移至componentDidUpdate酣衷。如果觸發(fā)某些回調(diào)函數(shù)時(shí)需要用到 DOM 元素的狀態(tài),則將對比或計(jì)算的過程遷移至getSnapshotBeforeUpdate次泽,然后在componentDidUpdate中統(tǒng)一觸發(fā)回調(diào)或更新狀態(tài)穿仪。


改變之后是不是發(fā)現(xiàn)變化很大,簡潔的多了; 以上純屬轉(zhuǎn)發(fā)意荤,僅供學(xué)習(xí)參考啊片,不足之處多多指教,程序猿努力學(xué)習(xí)中...

借鑒:掘金 誠身?https://juejin.im/post/5ae6cd96f265da0b9c106931

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末玖像,一起剝皮案震驚了整個(gè)濱河市紫谷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捐寥,老刑警劉巖笤昨,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異上真,居然都是意外死亡咬腋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門睡互,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事就珠】芸牵” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵妻怎,是天一觀的道長壳炎。 經(jīng)常有香客問我,道長逼侦,這世上最難降的妖魔是什么匿辩? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮榛丢,結(jié)果婚禮上铲球,老公的妹妹穿的比我還像新娘。我一直安慰自己晰赞,他們只是感情好稼病,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掖鱼,像睡著了一般然走。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戏挡,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天芍瑞,我揣著相機(jī)與錄音,去河邊找鬼褐墅。 笑死拆檬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掌栅。 我是一名探鬼主播秩仆,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猾封!你這毒婦竟也來了澄耍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤晌缘,失蹤者是張志新(化名)和其女友劉穎齐莲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磷箕,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡选酗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岳枷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芒填。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呜叫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殿衰,到底是詐尸還是另有隱情朱庆,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布闷祥,位于F島的核電站娱颊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凯砍。R本人自食惡果不足惜箱硕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悟衩。 院中可真熱鬧剧罩,春花似錦、人聲如沸局待。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钳榨。三九已至舰罚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薛耻,已是汗流浹背营罢。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饼齿,地道東北人饲漾。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像缕溉,于是被迫代替她去往敵國和親考传。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

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