useEffect — 화면이 그려진 다음에 할 일을 정합니다
Article
useState로 화면을 동적으로 바꾸는 방법은 배웠습니다. 그런데 실무에서는 화면을 그리는 것 외에 추가로 해야 할 일이 있습니다.
- 서버에서 데이터를 가져와야 합니다.
- 타이머를 설정해야 합니다.
- 스크롤 이벤트를 감지해야 합니다.
이런 작업을 **사이드 이펙트(Side Effect)**라고 부릅니다. 화면을 그리는 것과 직접적인 관련은 없지만, 컴포넌트가 동작하려면 반드시 필요한 작업들입니다.
useEffect는 이 사이드 이펙트를 관리하는 훅입니다.
useEffect란
useEffect는 화면이 그려진 후에 실행되는 코드를 작성하는 곳입니다.
비유하면, 무대 공연과 비슷합니다. 배우가 무대에 올라가서 자리를 잡은 다음(화면이 그려진 후), 조명이 켜지고 음악이 시작되는 것(useEffect 실행)입니다.
import { useState, useEffect } from "react";
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
// 화면이 그려진 후 서버에서 데이터를 가져옵니다
fetch("/api/user")
.then((res) => res.json())
.then((data) => setUser(data));
}, []);
if (!user) return <p>로딩 중...</p>;
return <p>{user.name}님 환영합니다</p>;
}
왜 필요할까요
"그냥 컴포넌트 함수 안에 바로 쓰면 안 되나요?"
컴포넌트 함수는 렌더링할 때마다 실행됩니다. API 호출을 함수 안에 바로 쓰면, 렌더링될 때마다 서버에 요청을 보내게 됩니다. 무한 반복에 빠질 수도 있습니다.
useEffect를 쓰면 언제 실행할지 제어할 수 있습니다. 처음 한 번만, 특정 값이 바뀔 때만, 같은 조건을 걸 수 있습니다.
의존성 배열
useEffect의 두 번째 인자로 들어가는 배열이 의존성 배열입니다. 이 배열이 useEffect의 실행 타이밍을 결정합니다.
빈 배열 []
useEffect(() => {
console.log("처음 한 번만 실행됩니다");
}, []);
컴포넌트가 처음 화면에 나타날 때 딱 한 번 실행됩니다. API 호출, 초기 설정 같은 작업에 씁니다.
값이 있는 배열 [value]
useEffect(() => {
console.log("count가 바뀔 때마다 실행됩니다");
}, [count]);
배열에 넣은 값이 바뀔 때마다 실행됩니다. 특정 상태에 반응해서 추가 작업을 해야 할 때 씁니다.
배열 없음
useEffect(() => {
console.log("렌더링될 때마다 실행됩니다");
});
의존성 배열을 아예 안 쓰면 매 렌더링마다 실행됩니다. 대부분의 경우 이렇게 쓸 일은 없습니다. 성능 문제가 생길 수 있으니 주의하세요.
클린업 함수
useEffect 안에서 정리(cleanup)가 필요한 작업이 있을 수 있습니다. 이벤트 리스너를 등록했으면 해제해야 하고, 타이머를 설정했으면 제거해야 합니다.
useEffect(() => {
function handleResize() {
console.log(window.innerWidth);
}
window.addEventListener("resize", handleResize);
// 클린업: 컴포넌트가 사라질 때 이벤트 리스너를 제거합니다
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
useEffect 안에서 함수를 리턴하면, 그 함수가 컴포넌트가 화면에서 사라질 때(또는 다음 effect가 실행되기 전에) 실행됩니다.
비유하면, 공연이 끝나면 조명을 끄고 음악을 멈추는 것과 같습니다. 무대를 깨끗이 정리하는 겁니다.
간단한 예시: 타이머
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => clearInterval(timer); // 클린업
}, []);
return <p>{seconds}초 경과</p>;
}
컴포넌트가 화면에 나타나면 1초마다 숫자가 올라가고, 화면에서 사라지면 타이머가 정리됩니다.
정리
- useEffect는 화면이 그려진 후 실행할 코드를 작성하는 곳입니다.
- 의존성 배열로 실행 타이밍을 제어합니다.
[]: 처음 한 번만[value]: value가 바뀔 때마다- 없음: 매 렌더링마다
- 클린업 함수로 이벤트 리스너, 타이머 등을 정리합니다.
- API 호출, 이벤트 등록, 타이머 같은 사이드 이펙트를 관리할 때 씁니다.
useState와 useEffect, 이 두 가지만 확실히 이해하면 React의 기본기는 갖춘 겁니다. 나머지 훅들은 이 두 개의 응용이라고 생각해도 됩니다.