React useEffect — side effect · cleanup
외부 세계와 동기화하는 Hook. 데이터 fetch·구독·timer — 그리고 가장 흔한 무한 루프 함정.
지금까지 다룬 컴포넌트는 "props 와 state 만 보고 JSX 그리기" 만 했다. 순수 함수. 그런데 실전 앱은 외부 세계와 통신해야 한다 — API 호출, WebSocket 구독, timer 시작, DOM 직접 조작, 로깅. 이런 걸 React 는 side effect (부작용) 라 부른다.
useEffect 는 side effect 를 안전한 시점에 실행하기 위한 Hook. 잘못 쓰면 무한 루프, 메모리 누수, 옛 데이터 사용 등 신나는 사고가 줄줄이. 이번 11편에서 한 번에 정리.
1. 언제 실행되나 — 렌더 직후
useEffect 첫 인자는 "렌더 후 실행할 함수". 두 번째 인자는 "언제 다시 실행할지" dependency array.
흐름 — 컴포넌트가 처음 마운트 → 화면에 "로딩..." 그려짐 → 그 직후 useEffect 실행 → fetch → setUser → state 변화 → 재렌더 → "user.name" 표시.
2. dependency array — 3가지 경우
두 번째 인자에 무엇을 넣냐에 따라 실행 빈도 결정.
react-hooks/exhaustive-deps) 가 자동 검사. 빠뜨리면 옛 값(stale closure) 사용 버그.
3. cleanup — return 함수의 진짜 의미
구독·timer 처럼 시작했으면 멈춰야 하는 작업은 cleanup function 으로. useEffect 콜백이 다른 함수 를 return 하면 그게 cleanup.
cleanup 이 호출되는 시점 — ① 컴포넌트가 언마운트될 때, ② dependency 가 바뀌어 effect 가 다시 실행되기 직전. ②가 핵심 — 옛 effect 의 구독을 끊고 새 effect 의 구독을 시작.
cleanup 안 쓰면 — Clock 컴포넌트가 사라져도 setInterval 이 계속 돌고 setTime 호출 시도 → React 콘솔 "Can't perform state update on unmounted component" 경고 + 메모리 누수.
4. 무한 루프 — 가장 흔한 함정 3종
모든 React 개발자가 한 번은 겪는다. 패턴 3개 박제.
함정 1 — dependency 빠뜨림 + state 변경
함정 2 — 객체/배열을 dependency 에
해결 — 부모가 useMemo 로 객체 메모이즈 (16편), 또는 효과 안에서 객체의 원시 값만 dependency 로:
함정 3 — state 를 다른 state 로 동기화
이건 무한 루프는 안 일어나지만 불필요한 재렌더 2번. "파생 값은 effect 가 아니라 계산" 이 React 의 정공법. effect 는 외부 세계 동기화 전용.
useEffect 가 손에 잡히면 인터랙티브 React 앱의 모든 부품이 완성. 12편부터는 같은 로직을 여러 컴포넌트에서 재사용하는 커스텀 Hook 패턴. React 의 진짜 우아함이 보이는 구간.
다음 글
React 교재 12편 — 커스텀 Hook 만들기. use- prefix, 로직 추출, 재사용 패턴. useEffect 의 진짜 응용.