🔄
EPISODE 02
Side Effect · 의존성 배열 · 클린업 · fetch 패턴
useEffect
Side Effect의 개념, useEffect의 3가지 의존성 배열 패턴, 클린업 함수, AbortController를 활용한 fetch 취소, 그리고 흔한 무한 루프 함정을 익힙니다.
ReactuseEffectside effect
소요 시간
⏱ 60분
난이도
📊 중급
선수 조건
🎯 react-01
결과물
안전한 데이터 fetch와 타이머·구독 정리
이 강의에서 배우는 것
- 1Side Effect 개념을 이해하고 useEffect 안에서 처리한다
- 2[] / [값] / 없음 — 3가지 의존성 패턴을 구분한다
- 3클린업 함수가 필요한 4가지 상황을 안다
- 4AbortController로 fetch를 안전하게 취소한다
- 5객체/배열 의존성으로 인한 무한 루프를 방지한다
1. Side Effect란
렌더링 외에 컴포넌트가 외부와 상호작용하는 모든 것 — 데이터 fetch, DOM 직접 조작, 이벤트 리스너, 타이머, 구독.
React 렌더링은 순수해야 합니다(같은 props → 항상 같은 JSX). Side Effect는 useEffect 안에서.
2. 의존성 배열 — 3가지 패턴
패턴 1: 의존성 배열 없음 → 매 렌더링
jsx
useEffect(() => {
console.log('렌더링될 때마다 실행');
}); // ⚠️ 거의 사용 안 함패턴 2: 빈 배열 → 마운트 시 한 번
jsx
useEffect(() => {
fetchInitialData();
}, []);패턴 3: 값이 있는 배열 → 값이 바뀔 때마다
jsx
useEffect(() => {
fetchUser(userId);
}, [userId]);3. 클린업 함수
jsx
useEffect(() => {
const timerId = setInterval(() => console.log('1초마다'), 1000);
return () => {
clearInterval(timerId);
console.log('타이머 정리!');
};
}, []);| 상황 | 클린업 |
|---|---|
| setInterval/setTimeout | clearInterval/clearTimeout |
| addEventListener | removeEventListener |
| WebSocket | socket.close() |
| fetch | AbortController.abort() |
4. 데이터 fetch 패턴
jsx
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const fetchUser = async () => {
try {
setIsLoading(true);
setError(null);
const r = await fetch(`/users/${userId}`, { signal: controller.signal });
if (!r.ok) throw new Error('실패');
setUser(await r.json());
} catch (err) {
if (err.name !== 'AbortError') setError(err.message);
} finally {
setIsLoading(false);
}
};
fetchUser();
return () => controller.abort();
}, [userId]);
if (isLoading) return <p>로딩 중...</p>;
if (error) return <p>오류: {error}</p>;
return <p>{user?.name}</p>;
}5. 무한 루프 주의
jsx
// ❌ 무한 루프 — count 변경 → effect → count 변경 → ...
useEffect(() => {
setCount(count + 1);
}, [count]);
// ✅ 함수형 업데이트
useEffect(() => {
setCount(prev => prev + 1);
}, []);
// ❌ 객체/배열 의존성 — 매 렌더링마다 새 참조
useEffect(() => {
fetchData(options);
}, [options]);
// ✅ useMemo / useCallback (강의06)으로 참조 유지