useEffect는 컴포넌트가 렌더링된 이후 실행되는 함수야.

비동기 처리나 사이드 이펙트를 다룰 때 자주 쓰이고, TypeScript와 함께 사용할 때는 특히 의존성 배열, 비동기 함수, cleanup 함수에 주의해야 해.


📘 예제 21: 의존성 배열의 타입 영향

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가 자동으로 타입 기반 체크해주므로 오류를 줄여줘.


📘 예제 22: 비동기 처리 함수

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를 붙이지 말고, 내부에서 별도 함수로 비동기 작업을 실행하는 구조로 작성해야 해.


📘 예제 23: fetch와 함께 쓰기

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 구조를 정확히 알고 있으면 타입 정의가 쉬워져.


📘 예제 24: cleanup 함수 타입

const Timer = () => {
  useEffect(() => {
    const id = setInterval(() => {
      console.log('1초마다 실행');
    }, 1000);

    // 컴포넌트 언마운트 시 실행되는 정리(cleanup) 함수
    return () => {
      clearInterval(id);
    };
  }, []);

  return <div>타이머 동작 중</div>;
};

✅ useEffect가 리턴하는 함수는 정리 함수로, 타이머나 이벤트 리스너를 해제할 때 사용해. setInterval은 NodeJS.Timeout 타입이므로 clearInterval 사용 가능.