前言
剛學(xué)React的時(shí)候才 React16.1 剛出來每多久胎源,那時(shí)候剛出來一個(gè)的鉤子函數(shù) componentDidCatch,可應(yīng)用于處理錯(cuò)誤邊界跟磨。但 React v16.3 又新增了兩個(gè)生命周期函數(shù)逃糟,前面寫的那篇總結(jié)好像有點(diǎn)過時(shí)笆焰,因此又總結(jié)了一下,做個(gè)補(bǔ)充氢妈。
一粹污、變動(dòng)情況
React v16.3 發(fā)布時(shí)除了全新的 context API 之外,還引入了兩個(gè)新的生命周期函數(shù):
- getDerivedStateFromProps
- getSnapshotBeforeUpdate
并且也確定了在v17.0版本將移除三個(gè)生命周期函數(shù):
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate首量。
總的來說就是移除了所有帶 will 的生命周期函數(shù)壮吩,也就是 render 之前的生命周期函數(shù)除了shouldUpdateComponent 之外的生命周期函數(shù)都被干掉了。
二加缘、變動(dòng)詳情
以我的理解鸭叙,React 生命周期的變動(dòng)主要是為了兩方面:
- 迎合 Fiber 架構(gòu)變動(dòng)的需求
- 規(guī)范開發(fā)者開發(fā)的行為
2.1 getDerivedStateFromProps
首先以前需要利用被刪除的那些生命周期函數(shù)才能實(shí)現(xiàn)的功能,都可以通過 getDerivedStateProps 的幫助來實(shí)現(xiàn)拣宏。
那 getDerivedStateProps 究竟是啥東西呢沈贝?首先 getDerivedStateProps 生命周期函數(shù)是一個(gè)靜態(tài)函數(shù),所以函數(shù)體內(nèi)不能訪問this勋乾。
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.translateX !== prevState.translateX) {
return {
translateX: nextProps.translateX,
};
}
return null;
}
這樣的函數(shù)其實(shí)表達(dá)的意思很明確宋下,我們?cè)谶@個(gè)函數(shù)內(nèi)部就好好的做個(gè)運(yùn)算就行了嗡善,其他的騷操作就別再這做了。
比如很多開發(fā)者很喜歡在 componentWillMount 進(jìn)行AJAX請(qǐng)求以獲取數(shù)據(jù)学歧,因?yàn)樗麄冋J(rèn)為 componentWillMount在render 之前執(zhí)行罩引,早一點(diǎn)執(zhí)行就早得到結(jié)果。但其實(shí)在 componentWillMount 中發(fā)起 AJAX 請(qǐng)求枝笨,不管多快得到結(jié)果袁铐,都趕不上首次 render 的速度,因此這種操作和可能會(huì)導(dǎo)致首屏無數(shù)據(jù)而導(dǎo)致白屏横浑。
另外對(duì)于 React16 架構(gòu)最大的變動(dòng)就是 Fiber 了昭躺,在 Fiber 架構(gòu)下啟用了啟用 async render 之后,render 之前的生命周期函數(shù)可能會(huì)被調(diào)用多次伪嫁,如果在 componentWillMount 進(jìn)行 AJAX 請(qǐng)求可能會(huì)導(dǎo)致無謂地多次調(diào)用AJAX领炫。
其次在 React v16.3 剛發(fā)布這個(gè)函數(shù)的時(shí)候,getDerivedStateFromProps 這個(gè)生命周期函數(shù)张咳,我在從它的名字來看的時(shí)候帝洪,還以為它主要是為了代替 componentWillReceiveProps 的,但進(jìn)過了解后發(fā)現(xiàn)脚猾,這樣說其實(shí)并不準(zhǔn)確葱峡。因?yàn)?componentWillReceiveProps 只在因?yàn)楦附M件而引發(fā)的Updating過程中才會(huì)被調(diào)用。而getDerivedStateFromProps在Updating和Mounting過程中都會(huì)被調(diào)用龙助。還需要注意的是砰奕,同樣是 Updating 過程,如果是因?yàn)樽陨磉M(jìn)行的 setState 或者 forceUpdate 所引發(fā)的渲染提鸟,getDerivedStateFromProps 也不會(huì)被調(diào)用军援。
這很容易引發(fā)一些問題,且讓人難以理解這種差異称勋,畢竟竟然可以在 updating 和 Mounting 過程中都可以調(diào)用胸哥,那么為什么在 setState 和 forceUpdate 發(fā)生時(shí)不會(huì)調(diào)用呢?且如果這樣的話赡鲜,那么在平時(shí)使用這個(gè)生命周期函數(shù)的時(shí)候空厌,需不需要單獨(dú)考慮不調(diào)用這個(gè)函數(shù)的時(shí)候需要怎么進(jìn)行處理,諸如此類的問題還有不少银酬。
也這是由于這個(gè)原因嘲更,React 團(tuán)隊(duì)很快就做出了調(diào)整,改正了這一點(diǎn)揩瞪,讓 getDerivedStateFromProps 無論是 Mounting 還是 Updating 還是自身組件的 setstate 或 forceUpdate 都會(huì)調(diào)用這個(gè)函數(shù)赋朦。這明顯到簡(jiǎn)單多了,非常好理解:只要進(jìn)行掛載或更新組件,都會(huì)調(diào)用 getDerivedStateFromProps 生命周期函數(shù)北发。
2.2 getSnapshotBeforeUpdate
除了 getDerivedStateFromProps 外纹因,React v16.3還引入了一個(gè)新的聲明周期函數(shù)getSnapshotBeforeUpdate。這函數(shù)會(huì)在render之后執(zhí)行琳拨,而執(zhí)行之時(shí)DOM元素還沒有被更新瞭恰,給了一個(gè)機(jī)會(huì)去獲取DOM信息,計(jì)算得到一個(gè)snapshot狱庇,這個(gè)snapshot會(huì)作為componentDidUpdate的第三個(gè)參數(shù)傳入惊畏。
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('#enter getSnapshotBeforeUpdate');
return 'foo';
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('#enter componentDidUpdate snapshot = ', snapshot);
}
上面這段代碼可以看出來這個(gè)snapshot怎么個(gè)用法,snapshot咋看還以為是組件級(jí)別的某個(gè)“快照”密任,其實(shí)可以是任何值颜启,到底怎么用完全看開發(fā)者自己,getSnapshotBeforeUpdate把snapshot返回浪讳,然后DOM改變缰盏,然后snapshot傳遞給componentDidUpdate。
官方給了一個(gè)例子淹遵,用getSnapshotBeforeUpdate來處理scroll口猜,坦白說,我也想不出其他更常用更好懂的需要getSnapshotBeforeUpdate的例子透揣,這個(gè)函數(shù)應(yīng)該大部分開發(fā)者都用不上济炎。(這是看程墨大佬的說法抄的,我還是沒搞清楚這個(gè)函數(shù)有啥用辐真。须尚。。o(╥﹏╥)o)
其他
總的來說這些生命周期函數(shù)是 React 團(tuán)隊(duì)試圖通過框架級(jí)別的 API 來約束或者說幫助開發(fā)者寫出可維護(hù)性更佳的 JavaScript 代碼侍咱。以前一些影響性能的操作耐床,到現(xiàn)在React好像完全不能忍受了,逼著大家寫好的代碼放坏,這其實(shí)挺不錯(cuò)的咙咽。
而這些生命周期函數(shù)的改動(dòng)也之一要到React 17 才會(huì)進(jìn)行實(shí)裝,且那些要移除的生命周期也不會(huì)完全廢棄淤年,只需要加上UNSATE_的前綴還是可以用的。