Jeff的隨手筆記

學習當一個前端工程師

0%

『Day 27』為什麼你可能不需要 useEffect

前言

還記得在學習 React 的過程中,一開始接觸到 useEffect 時,總是很興奮地想要把它用在各種地方。特別是當遇到任何跟資料處理或狀態更新相關的邏輯時,第一個反應就是:「啊!這裡要用 useEffect!」。但隨著開發經驗的累積,漸漸發現到並非所有情況都適合使用它。今天就讓我分享一下這些實務經驗。

useEffect:React 的「逃生艙」

useEffect 就像是 React 提供給我們的一個逃生艙,讓我們能夠跳出 React 的框架,主要用於處理需要與外部系統同步的情況。但在使用它之前,我們應該先問問自己:這個需求真的需要 useEffect 嗎?

適合使用 useEffect 的情況

  1. 與外部系統同步

    1
    2
    3
    4
    5
    6
    useEffect(() => {
    const data = localStorage.getItem('userData');
    if (data) {
    setUserData(JSON.parse(data));
    }
    }, []);
  2. 處理資料擷取的競態問題

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    useEffect(() => {
    let ignore = false;
    async function fetchData() {
    const result = await fetchUserData(userId);
    if (!ignore) {
    setData(result);
    }
    }
    fetchData();
    return () => {
    ignore = true;
    };
    }, [userId]);

常見的誤用情況

很多時候,我們其實不需要使用 useEffect。以下是一些常見的誤用案例:

  1. 資料轉換

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // ❌ 不建議這樣寫
    function Form() {
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const [fullName, setFullName] = useState('');

    useEffect(() => {
    setFullName(firstName + ' ' + lastName);
    }, [firstName, lastName]);
    }

    // ✅ 建議這樣寫
    function Form() {
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const fullName = firstName + ' ' + lastName;
    }
  2. 事件處理後的邏輯

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // ❌ 不建議這樣寫
    function ProductPage({ product, addToCart }) {
    useEffect(() => {
    if (product.isInCart) {
    showNotification(`已加入購物車:${product.name}`);
    }
    }, [product]);
    }

    // ✅ 建議這樣寫
    function ProductPage({ product, addToCart }) {
    function handleBuyClick() {
    addToCart(product);
    showNotification(`已加入購物車:${product.name}`);
    }
    }

使用 useEffect 時的注意事項

  1. 清理函式很重要

    1
    2
    3
    4
    5
    6
    7
    useEffect(() => {
    const timer = setInterval(() => {
    setCount(c => c + 1);
    }, 1000);

    return () => clearInterval(timer);
    }, []);
  2. 正確設定依賴項

    • 依賴項陣列要包含 effect 中使用到的所有響應式值
    • 可以使用 ESLint 規則來協助檢查

總結

useEffect 是個強大的工具,但不是萬靈丹。在使用它之前,我們應該先思考:

  • 這個邏輯是否真的需要「副作用」?
  • 是否有其他更適合的解決方案?
  • 使用 useEffect 是否會帶來不必要的複雜度?

記住,有時候最簡單的解決方案,反而是最好的選擇。