摘要:同步渲染的痛點當應用的組件樹特別龐大時,由于是單線程的,重新渲染一旦開始,中間不會停,如果這時候用戶去操作,比如輸入,點擊按鈕,此時頁面是沒有響應的。
React生命周期 基礎生命周期鉤子
constructor
如果你不初始化狀態,也不綁定方法,那么你就不需要為React組件實現構造函數。在這里初始化狀態可以直接對this.state賦值,在這里使用props時,應當通過this.props使用;如果組件內定義的方法不是采用箭頭函數默認綁定到組件實例上時,調用時應該用bind手動綁定。
componentWillMount(將要廢棄)
在react17版本前有效的生命周期鉤子,不能與新版鉤子混用(componentWillRecevieProps、componentWillUpdate也是如此);
有一種常見的誤區是在componentWillMount中請求數據可以避免第一次empty render,但實際中render在componentWillMount后立即執行,如果componentWillMount拉取的數據不能立即得到,那么二次渲染依然無法避免,這種情況下推薦在componentDidMount中請求數據。
所以總的來說沒啥用處。
render
render()方法是類組件唯一必須的方法,在該鉤子內,將React JSX 渲染為DOM節點。
render()函數應該是純的,意味著不應該改變組件的狀態,其每次調用都應返回相同的結果,同時它不會直接和瀏覽器交互
componentDidMount
在該鉤子內,render生成的DOM節點掛載到DOM樹中,在這里你可以通過ref取到DOM節點,有些需求下,可能需要DOM節點掛載后才能取到相應的屬性,例如DOM節點的尺寸等,你可以立即調用setState()。它將會觸發一次額外的渲染,但是它將在瀏覽器刷新屏幕之前發生。這保證了在此情況下即使render()將會調用兩次,用戶也不會看到中間狀態。
componentWillUnmount
componentWillUnmount()緊挨著在組件被卸載和銷毀之前調用。可以在該方法里處理任何必要的清理工作,例如解綁定時器,取消網絡請求,清理任何在componentDidMount環節創建的訂閱。
稍微進階的生命周期鉤子上述介紹的基本生命周期鉤子是上圖的左半部分,走完了一次初始渲染的流程,但React組件嵌套復用,當父組件更新或者組件自身狀態更新觸發子組件重新渲染時,合理的使用上圖右半部分的生命周期鉤子可以有效提升性能。
componentWillReceiveProps(nextProps)(將要廢棄)
componentWillReceiveProps()在裝載了的組件接收到新屬性前調用。可能當接收到新屬性后,通過if比較新舊Props不同,想要通過this.setState()來更新組件的狀態。
shouldComponentUpdate(nextProps, nextState)
當接收到新屬性或狀態時,shouldComponentUpdate() 在渲染前被調用。默認為true。該方法在初始化渲染或當使用forceUpdate()時并不會被調用。
適用場景是:你想在某些狀態或屬性變化時,通過this.props和nextProps以及this.state 和 nextState比較,來判斷是否需要重新渲染該組件,return fasle 不渲染,默認為true。不能setState。
有內建的React.PureComponent代替手寫shouldComponentUpdate()。PureComponent 對屬性和狀態執行淺比較,因而降低你略過必要更新的機會。
但如果你需要更精細的控制,那就自定義shouldComponentUpdate吧。
但是當你的state或props是嵌套很深的引用類型時,容易由于淺比較而出錯,而React文檔說我們不推薦做深相等檢測,或使用JSON.stringify()在shouldComponentUpdate()中,這是非常無效率的會傷害性能。所以你最好設計好自己的數據結構,不要讓數據嵌套太深。
componentWillUpdate(nextProps, nextState)
類似于componentWillMount,在nextProps, nextState生效前最后的一次準備機會,可以讀取DOM屬性,為componentDidUpdate作準備(使用場景少)。不能setState。
componentDidUpdate
組件更新后觸發,類似于componentDidMount的作用,可以在這里操作DOM,發起請求等。
參考鏈接:
React Lifecycle Methods- how and when to use them
React組件生命周期小結
static getDerivedStateFromProps(nextProps, prevState)
與舊的生命周期圖比較可以看出,getDerivedStateFromProps處于原來的componentWillMount與componentWillReceiveProps位置,而且this.setState()以及this.forceUpdate()也會觸發該鉤子。
該鉤子的主要作用是為了替代componentWillReceiveProps作用。
// Before class ExampleComponent extends React.Component { state = { isScrollingDown: false, }; componentWillReceiveProps(nextProps) { if (this.props.currentRow !== nextProps.currentRow) { this.setState({ isScrollingDown: nextProps.currentRow > this.props.currentRow, }); } } } // After class ExampleComponent extends React.Component { state = { isScrollingDown: false, lastRow: null, }; static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.currentRow !== prevState.lastRow) { return { isScrollingDown: nextProps.currentRow > prevState.lastRow, lastRow: nextProps.currentRow, }; } // Return null to indicate no change to state. return null; } }
與原有鉤子相比,getDerivedStateFromProps是一個靜態方法,無法訪問組件實例,如此限制了其使用范圍,防止不熟練的開發者自由發揮導致各種bug。該鉤子主要作用可以概括為接收props來改變state。
可以發現在使用getDerivedStateFromProps時,我們在state中多花了一個變量lastRow來保存prevProps,為什么設計鉤子的時候不在參數值加入prevProps呢? 官方文檔的解釋是:1.首次渲染也會觸發getDerivedStateFromProps,這意味著每次都需要對prevProps進行空置檢測,麻煩;2.不將prevProps傳入是為了節省內存。
getSnapshotBeforeUpdate(prevProps, prevState)
取代componenWillUpdate功能。
getSnapshotBeforeUpdate在最新的渲染輸出提交給DOM前將會立即調用。它讓你的組件能在當前的值可能要改變前獲得它們。這一生命周期返回的任何值將會 作為參數被傳遞給componentDidUpdate()。
class ScrollingList extends React.Component { listRef = null; getSnapshotBeforeUpdate(prevProps, prevState) { // Are we adding new items to the list? // Capture the current height of the list so we can adjust scroll later. if (prevProps.list.length < this.props.list.length) { return this.listRef.scrollHeight; } return null; } componentDidUpdate(prevProps, prevState, snapshot) { // If we have a snapshot value, we"ve just added new items. // Adjust scroll so these new items don"t push the old ones out of view. // (snapshot here is the value returned from getSnapshotBeforeUpdate) if (snapshot !== null) { this.listRef.scrollTop += this.listRef.scrollHeight - snapshot; } } render() { return ({/* ...contents... */}); } setListRef = ref => { this.listRef = ref; }; }
static getDerivedStateFromError()與componentDidCatch()
錯誤處理。。。
render phase 里產生異常的時候, 會調用 getDerivedStateFromError;
在 commit phase 里產生異常大的時候, 會調用 componentDidCatch。
componentDidCatch 是不會在服務器端渲染的時候被調用的 而getDerivedStateFromError 會
為何用推出新的鉤子,廢棄舊的鉤子?主要是為了適應將要推出的異步渲染,其次是避免之前生命周期鉤子的濫用。
同步渲染與異步渲染React Fiber 是在 v16 的時候引入的一個全新架構, 旨在解決異步渲染問題,但v16并沒有開啟。
同步渲染的痛點:當應用的組件樹特別龐大時,由于javaScript是單線程的,重新渲染一旦開始,中間不會停,如果這時候用戶去操作, 比如輸入, 點擊按鈕, 此時頁面是沒有響應的。 等更新完了, 你之前的那些輸入就會啪啪啪一下子出來了。函數調用棧如圖所示:
因為JavaScript單線程的特點,每個同步任務不能耗時太長,不然就會讓程序不會對其他輸入作出相應,React的更新過程就是犯了這個禁忌,而React Fiber就是要改變現狀。
Fiber 的做法是:分片。
把一個很耗時的任務分成很多小片,每一個小片的運行時間很短,雖然總時間依然很長,但是在每個小片執行完之后,都給其他任務一個執行的機會,這樣唯一的線程就不會被獨占,其他任務依然有運行的機會。 而維護每一個分片的數據結構, 就是Fiber。
用一張圖來展示Fiber 的碎片化更新過程
在React Fiber中,一次更新過程會分成多個分片完成,所以完全有可能一個更新任務還沒有完成,就被另一個更高優先級的更新過程打斷,這時候,優先級高的更新任務會優先處理完,而低優先級更新任務所做的工作則會完全作廢,然后等待機會重頭再來。
因為一個更新過程可能被打斷,所以React Fiber一個更新過程被分為兩個階段: render phase and commit phase.(可以從上文的生命周期圖中看到)
因為第一階段的過程會被打斷而且“重頭再來”,就會造成意想不到的情況。
比如說,一個低優先級的任務A正在執行,已經調用了某個組件的componentWillUpdate函數,接下來發現自己的時間分片已經用完了,于是冒出水面,看看有沒有緊急任務,哎呀,真的有一個緊急任務B,接下來React Fiber就會去執行這個緊急任務B,任務A雖然進行了一半,但是沒辦法,只能完全放棄,等到任務B全搞定之后,任務A重頭來一遍,注意,是重頭來一遍,不是從剛才中段的部分開始,也就是說,componentWillUpdate函數會被再調用一次。
在現有的React中,每個生命周期函數在一個加載或者更新過程中絕對只會被調用一次;在React Fiber中,不再是這樣了,第一階段中的生命周期函數在一次加載和更新過程中可能會被多次調用!。
總而言之就是:
render phase 可以被打斷, 大家不要在此階段做一些有副作用的操作,可以放心在commit phase 里做。
然后就是生命周期的調整, react 把你有可能在render phase 里做的有副作用的函數都改成了static 函數, 強迫開發者做一些純函數的操作。
全面了解 React 新功能: Suspense 和 Hooks
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109090.html
摘要:而生命周期鉤子,就是從生到死過程中的關鍵節點。異步渲染下的生命周期花了兩年時間祭出渲染機制。目前為這幾個生命周期鉤子提供了別名,分別是將只提供別名,徹底廢棄這三個大活寶。生命周期鉤子的最佳實踐是在這里初始化。 本文是『horseshoe·React專題』系列文章之一,后續會有更多專題推出來我的 GitHub repo 閱讀完整的專題文章來我的 個人博客 獲得無與倫比的閱讀體驗 生命周期...
摘要:卸載階段組件卸載和銷毀老版生命周期之前的生命周期初始化階段涉及個鉤子函數這些方法會在組件初始化的時候被調用,只跟實例的創建有關。 前言:React 的版本從 v15 到 v16.3 ,再到v16.4,現在最新的版本是 v16.8了。其中最大的變化可能是React Hooks的加入,而最令人困惑的卻是它的生命周期,新舊生命周期函數混雜在一起,難免會讓許多新來者有很多困惑。所以這一篇我們來...
摘要:我們目前的計劃是為不安全生命周期引入別名,和。從現在開始,只有新的生命周期名稱將起作用。從版本開始,更新以響應更改的推薦方法是使用新的靜態生命周期。 注釋:本文是根據React的官方博客翻譯而成(文章地址:https://reactjs.org/blog/2018...)。主要講述了React之后的更新方向,以及對之前生命周期所出現的問題的總結,之后的React將逐步棄用一些生命周期和...
摘要:組件生命周期構造方法是對類的默認方法,通過命令生成對象實例時自動調用該方法。該生命周期可以發起異步請求,并。后廢棄該生命周期,可以在中完成設置渲染組件是一個組件必須定義的生命周期,用來渲染。該生命周期內可以進行。 React組件生命周期 constructor( ) 構造方法 constructor是ES6對類的默認方法,通過 new 命令生成對象實例時自動調用該方法。并且,該方法是...
摘要:所以對于組件更新階段的組件生命周期,我們簡單提及并且提供一些資料給大家。這里為了知識的完整,補充關于更新階段的組件生命周期你可以通過這個方法控制組件是否重新渲染。大家對這更新階段的生命周期比較感興趣的話可以查看官網文檔。 React.js 小書 Lesson20 - 更新階段的組件生命周期 本文作者:胡子大哈本文原文:http://huziketang.com/books/react...
摘要:組件生命周期此文章適合之前的版本,,添加了一些新的生命周期函數,同時準備廢棄一些會造成困擾的生命周期函數。每個生命周期階段調用的鉤子函數會略有不同。 React組件生命周期 此文章適合 React@17 之前的版本,React@16.3.0,添加了一些新的生命周期函數,同時準備廢棄一些會造成困擾的生命周期函數。所有如果在React@17 發布之前,這篇文章還是適用的。新的生命周期請看官...
閱讀 3532·2021-10-09 09:41
閱讀 2739·2021-10-08 10:18
閱讀 2174·2021-09-10 10:51
閱讀 2674·2021-09-10 10:50
閱讀 771·2021-09-09 09:33
閱讀 3377·2021-09-06 15:14
閱讀 3012·2019-08-30 11:06
閱讀 3242·2019-08-29 14:04