React 初心者大補帖(4)

正確使用 `useEffect` 的姿勢

在學習 React 的過程中,useEffect 是許多初學者常常感到困惑的一個 Hook。今天的筆記會記錄一下:

  • useEffect 的基本概念
  • 使用時機
  • 潛藏陷阱

🔍 Effect 是什麼?

Effect(副作用)是指 除了 return 值之外還會與外部互動或產生更大影響的行為。這些通常包含:

  • 向伺服器發送資料(如 API 請求)
  • 註冊事件監聽器(如 `window.addEventListener``)
  • 操作 DOM(例如 document.title = "...")
  • 設定或清除定時器(如 setTimeout, setInterval

這些副作用行為通常會超出 React 元件本身的範疇,因此 React 提供了 useEffect 來集中管理這些副作用。

⚠️ Effect 可能造成的問題

如果沒有妥善管理 effect 的執行與清除,可能會出現以下問題:

  • 記憶體洩漏:例如註冊了事件但沒清除
  • 多次重複執行:依賴沒寫齊,導致每次 render 都重新執行
  • 畫面狀態錯亂:例如過時的資料仍被使用,造成顯示不一致
  • 效能低落:頻繁 re-render 導致效能下降

💡 useEffect 是什麼?

useEffect 是 React 中用來處理副作用的 Hook。它的主要功能有兩個:

  1. 執行副作用程式碼:如前述的 API 呼叫、DOM 操作等。
  2. 清除副作用:透過 useEffect 傳回的清除函式(cleanup function),可以在元件 unmount 或重新執行 effect 前清除先前的副作用,避免記憶體洩漏或非預期行為。
1
2
3
4
5
6
7
8
9
useEffect(() => {
  const timer = setInterval(() => {
    console.log("每秒執行一次");
  }, 1000);

  return () => {
    clearInterval(timer); // 清除副作用
  };
}, []);

🛠️ useEffect 的用法

基本語法如下:

1
2
3
4
5
6
useEffect(() => {
  // 副作用邏輯
  return () => {
    // 清除副作用邏輯(可選)
  };
}, [dependencies]);

📌 根據依賴的不同,行為會有所差異:

  • useEffect(someActions):沒有指定依賴陣列,每次 render 都會執行,即使狀態沒改變也一樣
  • useEffect(someActions, []):傳入空陣列作為依賴,在第一次 render 時執行一次,後續 re-render 時會被安全的跳過
  • useEffect(someActions, [foo, bar]):傳入依賴陣列,當 foo 或 bar 的值改變時才會重新執行 effect

❗安全的跳過 ≠ 保證會跳過

很多人會誤以為傳入 [] 就一定不會重新執行,但實際上:

  • 安全地跳過是指跳過沒問題、不跳過也沒問題:有時候依賴沒列齊(例如漏掉某個 context 或 props),會導致效果不如預期
  • dependencies 是效能優化的手段,而不是執行時機的主邏輯控制工具

最好的做法是:

寫出正確的 effect 邏輯,然後再優化 dependencies。

Built with Hugo
Theme Stack designed by Jimmy