useEffect
Effect 用來同步外部系統:抓 API、訂閱、操作不是 React 管的 DOM、設計時器。能在渲染時算出來的值,用普通變數或 useMemo 即可,不必寫 Effect。
基本寫法
import { useEffect, useState } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
async function load() {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
if (!cancelled) {
setUser(data);
}
}
load();
return () => {
cancelled = true;
};
}, [userId]);
if (!user) {
return <p>載入中…</p>;
}
return <h1>{user.name}</h1>;
}
- 第二個參數是依賴陣列。
userId變了才重跑;寫[]表示只在掛載時跑一次。 - 回傳的函式是清理:元件卸載或下次 Effect 前執行,避免競態把舊請求寫進新畫面。
- 開發模式加了
StrictMode時,Effect 可能掛載 → 清理 → 再掛載一次,用來檢查你有沒有寫清理。
漏掉依賴會讓 Effect 讀到過期的 props/state。ESLint 的 react-hooks/exhaustive-deps 就是在抓這個。
什麼時候不要用
| 想做的事 | 較適合的做法 |
|---|---|
| 依 props/state 算出顯示用字串 | 渲染時直接算 |
| 點按鈕才送出表單 | 事件處理函式裡 fetch |
| 父傳子資料 | props,不要 Effect 再 copy 一份 state |
| 兩個 state 永遠要一起變 | 合併成一個 state,或在事件裡一次 set |
官方特別提醒:看到「state 變了再 set 另一個 state」的 Effect,多半可以改成衍生值或事件處理。見 You Might Not Need an Effect。
與資料庫/路由
產品若用 Next.js 等框架,列表資料常在伺服器元件或 loader 裡抓,不一定要自己寫 useEffect + fetch。本頁講的是函式庫本身;選框架後以該框架的資料教學為準。
官方對照:Synchronizing with Effects。Net Ninja 播放清單有逐步拆 useEffect 的短片,見 YouTube 優質教學。