?? 如果還不了解 HTML 、 CSS和JS,可以參考本號下的 HTML21 天入門教程、 CSS 21 天入門教程和JS21天入門教程。
組件的生命周期指組件從創(chuàng)建到卸載的全過程。
在這個(gè)過程中的不同階段,內(nèi)置了一些函數(shù)用以執(zhí)行需要的邏輯處理。
React 的生命周期經(jīng)過版本的迭代,有了一些變化。
這里介紹的生命周期基于版本 18。
生命周期階段
組件的生命周期有以下三個(gè)階段:
- 掛載階段(Mounting):組件實(shí)例被創(chuàng)建和插入 DOM 樹的過程。
- 更新階段(Updating):組件被重新渲染的過程。
- 卸載階段(Unmounting):組件從 DOM 樹中被刪除的過程。
注:以上圖形來自于 https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/。
它的簡潔示意圖如下:
從縱向來看,整個(gè)過程劃分為 Render
階段和 Commit
階段:
Render
階段:純凈且不包含副作用,可能會被 React 暫停、中止或重新啟動(dòng)。Commit
階段:可以使用 DOM,運(yùn)行副作用,安排更新。
掛載階段(Mounting)
掛載階段的觸發(fā)時(shí)間,是在組件實(shí)例被創(chuàng)建和插入 DOM 中時(shí)。
在這個(gè)過程中,主要以實(shí)現(xiàn)組件狀態(tài)的初始化為主。
構(gòu)造函數(shù) constructor
構(gòu)造函數(shù)在組件初始化的時(shí)候觸發(fā)一次。它主要用于 設(shè)置初始化狀態(tài) 和 綁定成員函數(shù)上下文引用。
如果不初始化 state
或不進(jìn)行方法綁定,則不需要為 React 組件實(shí)現(xiàn)構(gòu)造函數(shù)。
在 constructor()
函數(shù)中不要調(diào)用 setState()
方法。
如果需要使用內(nèi)部 state
,直接在構(gòu)造函數(shù)中為 this.state
賦值初始 state
。
constructor(props) { super(props); // 不要在這里調(diào)用 this.setState() this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this);}
切記,只能在構(gòu)造函數(shù)中直接為 this.state
賦值。
static getDerivedStateFromProps
getDerivedStateFromProps
會在調(diào)用 render
方法之前調(diào)用,并且在初始掛載及后續(xù)更新時(shí)都會被調(diào)用。
它應(yīng)返回一個(gè)對象來更新 state
,如果返回 null
則不更新任何內(nèi)容。
該函數(shù)是靜態(tài)函數(shù),函數(shù)體內(nèi)無法訪問指向當(dāng)前組件實(shí)例的指針 this
。
渲染函數(shù) render
唯一的一定不能省略的函數(shù),必須有返回值。
它僅用于渲染的純函數(shù),返回值完全取決于 state
和 props
的變化。
如果返回 null
或 false
表示不渲染任何 DOM 元素。
此渲染函數(shù)并不做實(shí)際的渲染動(dòng)作(渲染到 DOM 樹),它返回的只是一個(gè) JSX 的描述對象(及組件實(shí)例)。
何時(shí)進(jìn)行真正的渲染是有 React 庫決定的。
而 React 則是要把所有組件返回的結(jié)果綜合起來,才能知道如何產(chǎn)生真實(shí)的 DOM 樹。
也就是說,只有調(diào)用所有組件的渲染函數(shù)之后,才有可能完成 DOM 裝載,這時(shí)候才會依次調(diào)用 componentDidMount
函數(shù)作為裝載的收尾。
保持 render()
純粹,可以使服務(wù)器端渲染更加切實(shí)可行,也使組件更容易被理解。
?? 如果 shouldComponentUpdate() 返回 false,則不會調(diào)用 render()。
掛載成功函數(shù) componentDidMount
componentDidMount
會在組件掛載后(插入 DOM 樹中)立即調(diào)用。
依賴于 DOM 節(jié)點(diǎn)的初始化應(yīng)該放在這里。
常用來處理比如:監(jiān)聽事件、獲取到真實(shí) DOM 和請求后臺接口等。
componentDidMount
通常用于加載外部數(shù)據(jù)(即發(fā)送網(wǎng)絡(luò)請求)。
之所以在 componentDidMount
中而不是在構(gòu)造函數(shù)中進(jìn)行數(shù)據(jù)請求的原因在于:如果數(shù)據(jù)加載完畢后,即 props
已經(jīng)有值了,但是組件還沒有渲染出來,會報(bào)錯(cuò)。
但是這里有一些把數(shù)據(jù)拉取提前到 constructor
函數(shù)的思路:在 contructor
函數(shù)中,通過 Promise
來進(jìn)行數(shù)據(jù)的請求,并且綁定到當(dāng)前實(shí)例對象上,然后在 componentDidMount
中執(zhí)行 Promise
把數(shù)據(jù)更新到 props 上。
此函數(shù)中允許使用 setState
改變組件內(nèi) State
。
更新階段(Updating)
屬性(Props
)或狀態(tài)(State
)的改變會觸發(fā)一次更新階段操作,但是組件未必會重新渲染,這取決于 shouldComponentUpdate
。
shouldComponentUpdate
shouldComponentUpdate
指定組件是否更新鉤子。
每當(dāng)組件因?yàn)?nbsp;state
和 props
變化而更新時(shí),在重新渲染前 shouldComponentUpdate
函數(shù)都會觸發(fā)。
目的是讓 React 知道當(dāng)前 state
或 props
的改變是否影響組件的渲染。
由于 React 父組件的更新,必然會導(dǎo)致子組件的更新,因此可以在子組件中通過手動(dòng)對比 props
與 nextProps
,state
與 nextState
來確定是否需要重新渲染子組件。
如果需要?jiǎng)t返回 true
,不需要?jiǎng)t返回 false
。該函數(shù)默認(rèn)返回 true
。
?? 請勿在 shouldComponentUpdate
函數(shù)中使用 setState
方法,會導(dǎo)致循環(huán)調(diào)用。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate
用于保存狀態(tài)快照。
它會在組件即將掛載時(shí)觸發(fā),它的觸發(fā)在 render
渲染函數(shù)之后。render
函數(shù)并沒有完成掛載操作,而是進(jìn)行構(gòu)建抽象 UI(也就是 Virtual DOM)的工作。
這使得組件能在發(fā)生更改之前從 DOM 中捕獲一些信息。
此組件返回的任何值將作為 componentDidUpdate
的第三個(gè)參數(shù)。
componentDidUpdate
componentDidUpdate
是更新完成函數(shù)。
componentDidUpdate
方法在組件更新完后被調(diào)用。
因?yàn)榻M件已經(jīng)重新渲染,所以這里可以對組件中的 DOM 進(jìn)行操作。
在比較了 this.props 和 nextProps 的前提下可以發(fā)送網(wǎng)絡(luò)請求。
在 componentDidUpdate
中使用 setState 時(shí),必須加 if 條件判斷 prevProps
、prevState
和 this.state
之間的數(shù)據(jù)變化。
這使得盡管在 componentDidUpdate
中調(diào)用了 setState
進(jìn)行再更新,但是直至條件不成立,就不會造成程序死循環(huán)。
卸載階段(Unmounting)
卸載階段主要是從 DOM 樹中刪除組件,它只有一個(gè) componentWillUnmount
函數(shù)。
componentWillUnmount
componentWillUnmount
是預(yù)卸載函數(shù)。
它在組件卸載和銷毀之前觸發(fā)。
可以利用 componentWillUnmount
方法去執(zhí)行任何清理類的任務(wù)。
比如,注銷事件監(jiān)聽器、取消網(wǎng)絡(luò)請求、取消定時(shí)器、解綁 DOM 事件等。
要注意的是,如果在該方法中調(diào)用 setState
,不會觸發(fā) render
。
函數(shù)組件的生命周期
函數(shù)組件是更徹底的狀態(tài)驅(qū)動(dòng)抽象,甚至沒有類組件生命周期的概念,只有一個(gè)狀態(tài),React 則負(fù)責(zé)同步到 DOM。
那么在函數(shù)組件中是如何做的呢?
答案是使用鉤子。
?? 鉤子(hook)是計(jì)算機(jī)程序設(shè)計(jì)術(shù)語。指通過攔截軟件模塊間的函數(shù)調(diào)用、消息傳遞、事件傳遞來修改或擴(kuò)展操作系統(tǒng)、應(yīng)用程序或其他軟件組件的行為的各種技術(shù)。處理被攔截的函數(shù)調(diào)用、事件、消息的代碼,被稱為鉤子(hook)。
至于如何使用鉤子,明天繼續(xù)。
總結(jié)
- ?? 組件的生命周期有三個(gè)階段:掛載階段、更新階段和卸載階段。
- ?? 渲染函數(shù) render 是唯一的一定不能省略的函數(shù),且必須有返回值。
- ?? 函數(shù)組件是更徹底的狀態(tài)驅(qū)動(dòng)抽象,通過使用鉤子實(shí)現(xiàn)生命周期的函數(shù)處理。
該文章在 2024/12/4 15:30:50 編輯過