Skip to main content

Component 的生命週期

1. Component 的三大生命週期

在 React 的 類別型元件 (Class Component) 中,生命週期 (Lifecycle) 是指元件從創建到銷毀的過程,這些過程被分為三大階段:

  1. 掛載 (Mounting)
    當元件被創建並插入到 DOM 中時,會經歷「掛載」階段。這是元件初次渲染的過程,適合用來初始化狀態或執行初始的資料請求。

  2. 更新 (Updating)
    當元件的 propsstate 改變時,會觸發「更新」階段。此階段會重新渲染元件,適合用來處理資料變化或更新 UI。

  3. 卸載 (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 可以模擬類別型元件的三大生命週期階段:

  1. 掛載 (Mounting)
    在 useEffect 中傳入一個空依賴陣列 [],表示只在元件掛載時執行一次。

  2. 更新 (Updating)
    在 useEffect 中指定依賴陣列(如 [count]),當依賴項改變時執行。

  3. 卸載 (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 現代開發的主流方式,比較直觀且易於維護。