React 生命週期方法 (Lifecycle Methods)
生命週期方法是 Class Component 的概念。在 Function Component 中,我們使用 useEffect 來處理類似的邏輯。本篇作為舊版語法的補充參考。
React Class Component 有一系列的生命週期方法,讓你可以在元件的不同階段執行程式碼。
生命週期階段
元件的生命週期分為三個階段:
- Mounting(掛載):元件被建立並插入 DOM
- Updating(更新):props 或 state 改變,觸發重新渲染
- Unmounting(卸載):元件從 DOM 中移除
Mounting 階段
當元件被建立並插入 DOM 時,會依序執行:
constructor(props)
constructor(props) {
super(props); // 必須呼叫
this.state = { count: 0 }; // 初始化 state
this.handleClick = this.handleClick.bind(this); // 綁定方法
}
用途:
- 初始化 state
- 綁定事件處理方法
render()
render() {
return <div>{this.state.count}</div>;
}
render() 是唯一必須實作的方法,用於描述 UI。
注意:不要在 render() 中修改 state 或執行副作用。
componentDidMount()
componentDidMount() {
// 元件已經掛載到 DOM
this.fetchData();
this.subscription = subscribeToData();
}
用途:
- 發送 API 請求
- 設定訂閱
- 操作 DOM
對應的 Hook:
useEffect(() => {
// componentDidMount 的邏輯
}, []) // 空依賴陣列 = 只在掛載時執行
Updating 階段
當 props 或 state 改變時,會依序執行:
shouldComponentUpdate(nextProps, nextState)
shouldComponentUpdate(nextProps, nextState) {
// 回傳 true 繼續渲染,回傳 false 跳過渲染
return nextProps.id !== this.props.id;
}
用途:效能優化,決定是否需要重新渲染。
對應的方式: 使用 React.memo 或 React.PureComponent
render()
重新執行 render() 產生新的 UI。
componentDidUpdate(prevProps, prevState)
componentDidUpdate(prevProps, prevState) {
// 元件已更新
if (prevProps.userId !== this.props.userId) {
this.fetchUser(this.props.userId);
}
}
用途:
- 根據 props 變化執行操作
- 更新後操作 DOM
對應的 Hook:
useEffect(() => {
// 當 userId 改變時執行
fetchUser(userId)
}, [userId])
Unmounting 階段
當元件從 DOM 中移除時執行:
componentWillUnmount()
componentWillUnmount() {
// 清理工作
this.subscription.unsubscribe();
clearInterval(this.timerID);
}
用途:
- 取消訂閱
- 清除計時器
- 取消 API 請求
對應的 Hook:
useEffect(() => {
const subscription = subscribeToData()
// 清理函式 = componentWillUnmount
return () => {
subscription.unsubscribe()
}
}, [])
Error Handling
componentDidCatch(error, info)
componentDidCatch(error, info) {
// 捕捉子元件的錯誤
console.error(error);
logErrorToService(error, info.componentStack);
}
static getDerivedStateFromError(error)
static getDerivedStateFromError(error) {
// 更新 state 以顯示錯誤 UI
return { hasError: true };
}
這兩個方法用於建立 錯誤邊界。
生命週期圖解
Mounting:
constructor → render → componentDidMount
Updating:
shouldComponentUpdate → render → componentDidUpdate
Unmounting:
componentWillUnmount
生命週期方法對應 Hooks
| Class 生命週期 | Hook 對應方式 |
|---|---|
constructor | useState 初始值、useRef |
componentDidMount | useEffect(() => {}, []) |
componentDidUpdate | useEffect(() => {}, [deps]) |
componentWillUnmount | useEffect 的清理函式 |
shouldComponentUpdate | React.memo |
完整範例:Class vs Function
Class Component
class Timer extends Component {
constructor(props) {
super(props)
this.state = { seconds: 0 }
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState((prev) => ({ seconds: prev.seconds + 1 }))
}, 1000)
}
componentWillUnmount() {
clearInterval(this.interval)
}
render() {
return <p>經過時間:{this.state.seconds} 秒</p>
}
}
Function Component(相同功能)
function Timer() {
const [seconds, setSeconds] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1)
}, 1000)
return () => clearInterval(interval)
}, [])
return <p>經過時間:{seconds} 秒</p>
}
已廢棄的生命週期方法
以下方法已被廢棄,不應再使用:
→ 使用componentWillMountconstructor或componentDidMount→ 使用componentWillReceivePropsstatic getDerivedStateFromProps→ 使用componentWillUpdategetSnapshotBeforeUpdate