useEffect
는 컴포넌트가 렌더링된 이후 실행되는 함수야.
비동기 처리나 사이드 이펙트를 다룰 때 자주 쓰이고, TypeScript와 함께 사용할 때는 특히 의존성 배열, 비동기 함수, cleanup 함수에 주의해야 해.
import { useEffect, useState } from 'react';
const DocumentTitle = () => {
const [count, setCount] = useState(0);
// count가 바뀔 때마다 실행됨
useEffect(() => {
document.title = `카운트: ${count}`;
}, [count]); // ✅ 의존성 배열: count
return (
<button onClick={() => setCount(count + 1)}>카운트 증가</button>
);
};
✅ 의존성 배열에 count를 빼먹으면 useEffect 내부에서 stale 값이 참조될 수 있어.
ESLint가 자동으로 타입 기반 체크해주므로 오류를 줄여줘.
useEffect
내에서는 직접 async
함수를 쓸 수 없고, 내부에 비동기 함수를 만들어 호출해야 해.
const FetchUser = () => {
const [name, setName] = useState<string>('');
useEffect(() => {
const fetchData = async () => {
const res = await fetch('/api/user');
const data = await res.json();
setName(data.name);
};
fetchData();
}, []);
return <h2>사용자 이름: {name}</h2>;
};
✅ useEffect 자체에는 async를 붙이지 말고, 내부에서 별도 함수로 비동기 작업을 실행하는 구조로 작성해야 해.
type Todo = {
id: number;
title: string;
};
const TodoList = () => {
const [todos, setTodos] = useState<Todo[]>([]);
useEffect(() => {
fetch('<https://jsonplaceholder.typicode.com/todos?_limit=5>')
.then((res) => res.json())
.then((data: Todo[]) => setTodos(data));
}, []);
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
✅ fetch 결과에 타입을 붙여서 data: Todo[]로 안전하게 처리. JSON 구조를 정확히 알고 있으면 타입 정의가 쉬워져.
const Timer = () => {
useEffect(() => {
const id = setInterval(() => {
console.log('1초마다 실행');
}, 1000);
// 컴포넌트 언마운트 시 실행되는 정리(cleanup) 함수
return () => {
clearInterval(id);
};
}, []);
return <div>타이머 동작 중</div>;
};
✅ useEffect가 리턴하는 함수는 정리 함수로, 타이머나 이벤트 리스너를 해제할 때 사용해. setInterval은 NodeJS.Timeout 타입이므로 clearInterval 사용 가능.