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