ReactJS - 使用 useEffect:初学者的全面指南
你好,未来的 React 巫师們!今天,我們將踏上一段令人興奮的旅程,探索 React 中的 useEffect
。如果你是編程新手,別擔心——我會成為你的友好導遊,我們會一步一步地學習。在本教程結束時,你將能像專業人士一樣熟練使用 useEffect
!
useEffect 是什麼?
在我們深入之前,讓我們先了解 useEffect
的相關知識。想像你正在烤蛋糕。你混合食材,放入烤箱,然後呢?你可能會想設定一個計時器,對吧?這就是 useEffect
在 React 中的作用。它讓你在组件中執行“副作用”。
副作用是组件除了渲染 UI 的主要任務外還會發生的行為。這些可能包括:
- 從 API 獲取數據
- 手動更改 DOM
- 設置訂閱
現在,讓我們來深入了解!
useEffect 的簽名
useEffect
钩子有一種特定的寫法。讓我們分解一下:
useEffect(() => {
// 你的副作用代碼在這裡
}, [dependencies]);
這裡的每部分意義如下:
-
useEffect
:我們正在使用的钩子名稱。 -
() => { ... }
:這是一個箭頭函數,我們在裡面放置副作用代碼。 -
[dependencies]
:這是一個可選數組,我們在裡面列出副作用依賴的任何值。
讓我們看一個簡單的例子:
import React, { useEffect, useState } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div>秒數:{seconds}</div>;
}
在這個例子中,我們創建了一個簡單的計時器。useEffect
钩子設置了一個間隔,每秒增加我們的 seconds
狀態。空的依賴數組 []
意味著這個副作用只會在组件挂载時運行一次。
Effect 钩子的特性
現在,我們已經看到了一個基本示例,讓我們探索一下副作用钩子的關鍵特性:
- 時間:默認情況下,副作用在每次渲染後運行。
- 條件執行:我們可以使用依賴數組控制副作用運行的時間。
- 清理:副作用可以返回一個清理函數以防止記憶體泄漏。
讓我們詳細看看這些特性。
時間
默認情況下,useEffect
在每次渲染後運行。這意味著如果你在副作用中更新狀態,它可能會導致無限循環!以下是一個不該這麼做的例子:
function BadExample() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1); // 這會導致無限循環!
});
return <div>{count}</div>;
}
條件執行
為了防止副作用不必要地運行,我們可以提供一個依賴數組:
function ConditionalEffect({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(data => setUser(data));
}, [userId]);
return <div>{user ? user.name : '加載中...'}</div>;
}
在這個例子中,副作用只會在 userId
改變時運行。
清理
有些副作用需要清理以防止記憶體泄漏。以下是如何進行的:
function CleanupExample() {
useEffect(() => {
const subscription = subscribeToSomething();
return () => {
subscription.unsubscribe();
};
}, []);
return <div>我訂閱了!</div>;
}
從副作用返回的函數將在组件卸载時被調用。
使用 Effect 獲取數據
useEffect
的一个常见用途是從 API 獲取數據。讓我們看一個例子:
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, []);
if (loading) return <div>加載中...</div>;
if (error) return <div>錯誤:{error.message}</div>;
return <div>數據:{JSON.stringify(data)}</div>;
}
這個组件在挂载时获取数据,处理加载和错误状态,并在数据准备就绪时显示数据。
DOM 更改
useEffect
也可以用来直接操作 DOM。以下是一个例子:
function DOMManipulator() {
useEffect(() => {
const element = document.getElementById('my-element');
element.style.color = 'red';
return () => {
element.style.color = '';
};
}, []);
return <div id="my-element">我是紅色的!</div>;
}
这个副作用在组件挂载时将元素颜色改为红色,并在组件卸载时重置颜色。
清理函數
我們已經接触到了清理函数,但讓我們更深入地了解。清理函数对于防止記憶體泄漏和避免不必要的行为至关重要。以下是一个更复雜的例子:
function WindowResizer() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <div>窗口宽度:{windowWidth}px</div>;
}
在这个例子中,我们在组件挂载时添加了一个事件监听器,并在组件卸载时移除它。这防止了监听器在我们不再需要它时继续存在。
總結
讓我們總結一下我們學到的關於 useEffect
的知識:
特性 | 描述 |
---|---|
簽名 | useEffect(() => { ... }, [dependencies]) |
時間 | 默認情况下在每次渲染后运行 |
條件執行 | 使用依賴數組控制副作用運行的時間 |
清理 | 從副作用返回的函數用於清理 |
數據获取 | 可以用来从 API 获取数据 |
DOM 更改 | 可以直接操作 DOM |
清理函數 | 对于防止記憶體泄漏至关重要 |
就这样!你已经迈出了探索 useEffect
的第一步。记住,就像任何强大的工具一样,它需要练习才能掌握。所以不要害怕实验和犯错误——这是我们所有人学习的途径。快乐编码,愿你的副作用总是干净,组件总是响应式!
Credits: Image by storyset