文章

useEffect 介紹

useEffect 介紹

useEffect 是 React 中的一個 Hook,允許你在函數型組件中執行副作用操作。副作用操作通常是指那些會影響組件之外的事物,如數據請求、訂閱、DOM 操作或手動更改瀏覽器 API 等。

在類別組件中,這些副作用操作通常是在 componentDidMountcomponentDidUpdatecomponentWillUnmount 等生命週期方法中處理。而在函數型組件中,useEffect 將這些功能整合到了同一個 API 中。


useEffect 的基本用法

語法:

1
2
3
4
5
6
useEffect(() => {
  // 副作用邏輯
  return () => {
    // 清理邏輯(可選)
  };
}, [dependencies]);
  • 副作用邏輯:這段代碼在組件渲染後執行,可以是數據請求、DOM 操作等。
  • 清理邏輯:可選,當組件卸載或依賴項發生變化時執行,用來清理之前的副作用。
  • [dependencies]:依賴項數組,只有當數組中的值發生變化時,副作用邏輯才會重新執行。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `你點擊了 ${count} 次`;
  }, [count]); // 只有 count 改變時,副作用才會執行

  return (
    <div>
      <p>你點擊了 {count}</p>
      <button onClick={() => setCount(count + 1)}>點擊我</button>
    </div>
  );
}

export default Counter;

在這個範例中:

  • 每次 count 值發生變化時,useEffect 中的副作用代碼會執行,更新頁面的標題顯示當前的點擊次數。
  • 依賴項 [count] 表示只有當 count 發生變化時,副作用才會重新執行。

1. 依賴項數組

useEffect 的第二個參數是一個依賴項數組,用來告訴 React 只有當某些值改變時才重新執行副作用邏輯。根據依賴項的不同設置,useEffect 有以下三種情況:

(1) 沒有依賴項數組

如果不傳入第二個參數,副作用會在每次組件渲染後都執行(相當於每次 componentDidUpdate 都會執行),這可能會導致不必要的副作用執行。

1
2
3
useEffect(() => {
  console.log('每次渲染後都執行');
});

(2) 空依賴項數組

如果依賴項數組為空,則副作用只會在組件第一次掛載(componentDidMount)和最後卸載(componentWillUnmount)時執行一次。

1
2
3
4
5
6
useEffect(() => {
  console.log('只在組件掛載時執行');
  return () => {
    console.log('組件卸載時執行');
  };
}, []);

(3) 具體依賴項

當提供具體的依賴項時,副作用只會在依賴項發生變化時執行。這是最佳的性能優化方式,避免了不必要的副作用執行。

1
2
3
useEffect(() => {
  console.log('count 改變時執行');
}, [count]);

2. 清理副作用

在某些情況下,我們需要在組件卸載或依賴項改變之前清理之前的副作用。例如,在訂閱或設置計時器時,我們應該在組件卸載時取消訂閱或清除計時器,這樣可以避免內存洩漏。useEffect 可以返回一個清理函數來執行這個操作。

範例:清除計時器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(prev => prev + 1);
    }, 1000);

    return () => {
      clearInterval(interval);  // 在組件卸載時清除計時器
    };
  }, []);

  return <p>計時器: {seconds}</p>;
}

export default Timer;

在這個範例中:

  • 每次 useEffect 被執行時,設置一個計時器,計時器每秒更新一次 seconds 狀態。
  • 當組件卸載或重新渲染時,return 的清理函數會清除計時器,避免內存洩漏。

3. 多個 useEffect

你可以在一個組件中使用多個 useEffect,每個 useEffect 都可以負責不同的副作用操作。React 會按照它們出現在代碼中的順序依次執行這些副作用。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  // 更新頁面標題
  useEffect(() => {
    document.title = `你點擊了 ${count} 次`;
  }, [count]);

  // 每次 name 改變時執行
  useEffect(() => {
    console.log(`名字改變為: ${name}`);
  }, [name]);

  return (
    <div>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button onClick={() => setCount(count + 1)}>點擊我</button>
    </div>
  );
}

export default Example;

在這個範例中:

  • 第一個 useEffect 用來更新頁面的標題,當 count 改變時觸發。
  • 第二個 useEffect 用來監聽 name 的變化,當輸入框的內容變化時觸發。

4. useEffect 的常見應用場景

  • 數據請求useEffect 常用於在組件掛載後進行數據請求(API 調用),然後將結果存儲到 state 中。
  • 訂閱/取消訂閱:在組件掛載時訂閱事件(如 WebSocket 連接),並在卸載時取消訂閱。
  • 手動 DOM 操作:更新 DOM 元素(如設置頁面標題、滾動位置等)。
  • 設置/清除計時器:設置間隔計時器並在卸載時清除計時器。

總結

useEffect 是 React 中處理副作用的強大工具,它讓函數型組件能夠實現類似類別組件的生命週期功能。通過正確使用依賴項數組和清理副作用,你可以有效地管理組件的狀態更新、數據請求和其他副作用操作。

本文章以 CC BY 4.0 授權