Component 的生命週期
1. Component 的三大生命週期
在 React 的 類別型元件 (Class Component) 中,生命週期 (Lifecycle) 是指元件從創建到銷毀的過程,這些過程被分為三大階段:
-
掛載 (Mounting)
當元件被創建並插入到 DOM 中時,會經歷「掛載」階段。這是元件初次渲染的過程,適合用來初始化狀態或執行初始的資料請求。 -
更新 (Updating)
當元件的 props 或 state 改變時,會觸發「更新」階段。此階段會重新渲染元件,適合用來處理資料變化或更新 UI。 -
卸載 (Unmounting)
當元件從 DOM 中移除時,會進入「卸載」階段。這是清理資源(如清除計時器、取消網路請求等)的時機。
以下是每個階段的詳細說明,以及對應的生命週期方法,並附上完整的程式碼範例,方便你跟著操作。
1-1 掛載 (Mounting)
在這個階段,React 會將元件初始化並插入到 DOM 中。涉及的生命週期方法有:
-
constructor()
用來初始化 state 或綁定事件處理函數。 -
static getDerivedStateFromProps(props, state)
靜態方法,用來根據 props 更新 state(較少使用)。 -
render()
負責渲染元件的 UI,回傳 JSX。 -
componentDidMount()
元件掛載到 DOM 後立即執行,適合發送 API 請求或設置計時器。
程式碼範例:掛載階段
import React, { Component } from "react";
class MountingExample extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
console.log("1. constructor: 元件正在初始化");
}
static getDerivedStateFromProps(props, state) {
console.log("2. getDerivedStateFromProps: 檢查 props 與 state");
return null; // 回傳 null 表示不更新 state
}
componentDidMount() {
console.log("4. componentDidMount: 元件已掛載到 DOM");
// 模擬 API 請求
setTimeout(() => {
this.setState({ count: this.state.count + 1 });
}, 1000);
}
render() {
console.log("3. render: 渲染元件");
return (
<div>
<h1>掛載階段範例</h1>
<p>計數: {this.state.count}</p>
</div>
);
}
}
export default MountingExample;
說明:
-
constructor:初始化
state.count
為 0,並輸出日誌。 -
getDerivedStateFromProps:檢查 props 和 state,這裡僅輸出日誌,無實際更新。
-
render:渲染 JSX,顯示當前計數。
-
componentDidMount:模擬一個 1 秒後更新計數的行為,展示元件掛載後的初始化工作。
1-2 更新 (Updating)
當元件的 props 或 state 改變時,React 會重新渲染元件,觸發更新階段。涉及的生命週期方法有:
-
static getDerivedStateFromProps(props, state)
與掛載階段相同,用來根據 props 更新 state。 -
shouldComponentUpdate(nextProps, nextState)
決定是否需要重新渲染元件,回傳布林值(預設 true)。 -
render()
重新渲染 UI。 -
getSnapshotBeforeUpdate(prevProps, prevState)
在 DOM 更新前捕捉當前狀態(如滾動位置),回傳值會傳給 componentDidUpdate。 -
componentDidUpdate(prevProps, prevState, snapshot)
元件更新後執行,適合執行與更新相關的操作。
程式碼範例:更新階段
import React, { Component } from "react";
class UpdatingExample extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
static getDerivedStateFromProps(props, state) {
console.log("1. getDerivedStateFromProps: 檢查 props 與 state");
return null;
}
shouldComponentUpdate(nextProps, nextState) {
console.log("2. shouldComponentUpdate: 決定是否重新渲染");
return true; // 回傳 true 允許更新
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("4. getSnapshotBeforeUpdate: 捕捉更新前的狀態");
return "捕捉到的快照";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("5. componentDidUpdate: 元件已更新", snapshot);
}
render() {
console.log("3. render: 重新渲染元件");
return (
<div>
<h1>更新階段範例</h1>
<p>計數: {this.state.count}</p>
<button onClick={this.handleClick}>增加計數</button>
</div>
);
}
}
export default UpdatingExample;
說明:
-
handleClick:點擊按鈕會更新
state.count
,觸發更新階段。 -
shouldComponentUpdate:這裡回傳 true,允許元件更新。
-
getSnapshotBeforeUpdate:模擬捕捉快照,回傳一個字串。
-
componentDidUpdate:接收快照並輸出日誌,展示更新後的行為。
1-3 卸載 (Unmounting)
當元件從 DOM 中移除時,會進入卸載階段。涉及的生命週期方法只有一個:
componentWillUnmount()
用來清理資源,如清除計時器、取消訂閱或網路請求。
程式碼範例:卸載階段
import React, { Component } from "react";
class UnmountingExample extends Component {
componentDidMount() {
console.log("componentDidMount: 元件已掛載");
this.timer = setInterval(() => {
console.log("計時器運行中...");
}, 1000);
}
componentWillUnmount() {
console.log("componentWillUnmount: 元件即將卸載");
clearInterval(this.timer); // 清理計時器
}
render() {
return <h1>卸載階段範例</h1>;
}
}
export default UnmountingExample;
說明:
-
componentDidMount:設置一個每秒輸出的計時器。
-
componentWillUnmount:在元件卸載時清除計時器,防止記憶體洩漏。
2. Function Component 沒有提供生命週期 API
函數型元件 (Function Component) 本身並沒有像類別型元件這樣的生命週期方法,但 React 提供了 Hooks 來模擬類似的功能,特別是 useEffect Hook。以下是詳細說明:
為什麼函數型元件沒有生命週期 API?
-
函數型元件是純函數,設計上更簡單,沒有實例化的概念,因此不直接提供 componentDidMount、componentDidUpdate 等方法。
-
React 透過 Hooks(如 useEffect、useState)來處理生命週期相關的邏輯,讓程式碼更簡潔且易於維護。
使用 useEffect 模擬生命週期
useEffect 可以模擬類別型元件的三大生命週期階段:
-
掛載 (Mounting)
在 useEffect 中傳入一個空依賴陣列 [],表示只在元件掛載時執行一次。 -
更新 (Updating)
在 useEffect 中指定依賴陣列(如 [count]),當依賴項改變時執行。 -
卸載 (Unmounting)
在 useEffect 中回傳一個清理函數,該函數會在元件卸載時執行。
程式碼範例:使用 useEffect 模擬生命週期
import React, { Component } from "react";
class UnmountingExample extends Component {
componentDidMount() {
console.log("componentDidMount: 元件已掛載");
this.timer = setInterval(() => {
console.log("計時器運行中...");
}, 1000);
}
componentWillUnmount() {
console.log("componentWillUnmount: 元件即將卸載");
clearInterval(this.timer); // 清理計時器
}
render() {
return <h1>卸載階段範例</h1>;
}
}
export default UnmountingExample;
說明:
-
第一個 useEffect:模擬 componentDidMount,僅在掛載時執行一次。
-
第二個 useEffect:模擬 componentDidUpdate,當 count 改變時執行。
-
第三個 useEffect:模擬 componentWillUnmount,回傳清理函數在元件卸載時執行。
總結
-
類別型元件 提供明確的生命週期方法(如 componentDidMount、componentDidUpdate、componentWillUnmount),適合需要精細控制的場景。
-
函數型元件 沒有傳統生命週期 API,但透過 useEffect Hook 能靈活模擬掛載、更新、卸載的行為,程式碼更簡潔。
-
建議初學者優先學習函數型元件與 Hooks,因為這是 React 現代開發的主流方式,比較直觀且易於維護。