티스토리 뷰

300x250

React를 공부하다 보면 useState 다음으로 가장 많이 막히는 Hook이 바로 useEffect입니다. 문법 자체는 짧아 보이는데, 막상 써보면 “이게 왜 두 번 실행되지?”, “의존성 배열을 비우면 뭐가 달라지지?”, “API 호출은 어디에 넣어야 하지?” 같은 질문이 한꺼번에 생깁니다.

특히 입문자 입장에서는 아래 포인트에서 많이 헷갈립니다.

  • useEffect는 정확히 언제 실행되는가?
  • 의존성 배열은 왜 필요한가?
  • 빈 배열 []은 무슨 의미인가?
  • 무한 렌더링은 왜 생기고 어떻게 막아야 하는가?

이번 글에서는 React 입문자가 가장 자주 찾는 useEffect 사용법 정리를 기준으로, 실행 시점 → 의존성 배열 → API 호출 → cleanup → 자주 하는 실수까지 한 번에 정리하겠습니다.

핵심 요약
useEffect는 렌더링 이후 실행해야 하는 작업을 처리하는 Hook입니다.
의존성 배열은 effect가 다시 실행될 조건을 정하는 역할을 합니다.
가장 많이 쓰는 예는 API 호출, 이벤트 등록, 타이머 처리, 외부 상태 동기화입니다.
즉 useEffect는 화면을 그리는 Hook이 아니라, 렌더링 이후 필요한 부수 작업(side effect)을 관리하는 Hook이라고 보면 됩니다.
728x90
쉬운 정의
useEffect는 렌더링이 끝난 뒤 실행해야 하는 작업을 넣는 곳입니다.

React 컴포넌트는 먼저 화면을 그립니다. 그런데 어떤 작업은 화면을 그리는 도중이 아니라, 화면이 그려진 다음에 실행해야 합니다.

예를 들면 아래 같은 것들입니다.

  • 서버에서 데이터 가져오기
  • 이벤트 리스너 등록하기
  • setInterval 같은 타이머 시작하기
  • props나 state 변화에 맞춰 외부 동작 연결하기

이런 작업을 처리하는 대표적인 Hook이 useEffect입니다.

useEffect는 렌더링 이후 필요한 부수 작업을 실행하는 Hook입니다.

즉 useEffect를 이해할 때는 “언제 화면이 바뀌는가?”보다 “렌더링 후 어떤 작업을 연결해야 하는가?”로 보면 훨씬 쉽습니다.

useEffect 기본 문법과 실행 시점
의존성 배열을 어떻게 넣느냐에 따라 실행 시점이 달라집니다.

가장 기본적인 형태는 아래와 같습니다.

import { useEffect } from 'react';

useEffect(() => {
  console.log('effect 실행');
}, []);

핵심은 두 번째 인자인 의존성 배열입니다.

형태 실행 시점
useEffect(() => { ... }) 렌더링될 때마다 실행
useEffect(() => { ... }, []) 처음 마운트될 때 한 번 실행
useEffect(() => { ... }, [value]) value가 바뀔 때마다 실행
function Example({ userId }) {
  useEffect(() => {
    console.log('처음 렌더링되거나 userId가 바뀔 때 실행');
  }, [userId]);

  return <div>예제</div>;
}
중요한 관점
useEffect는 "언제 실행할지"보다 어떤 값이 바뀌었을 때 다시 실행할지를 기준으로 이해하는 편이 훨씬 쉽습니다.
의존성 배열은 왜 중요한가?
useEffect를 어렵게 만드는 핵심이지만, 반대로 가장 중요한 기준이기도 합니다.

의존성 배열은 effect 안에서 사용하는 값 중 어떤 값이 바뀌면 다시 effect를 실행할지 정하는 역할을 합니다.

쉽게 보면 이렇게 이해할 수 있습니다.

렌더링 후 effect 실행
 ↓
배열 안 값 변화 감시
 ↓
값이 바뀌면 다시 실행

예를 들어 검색어가 바뀔 때마다 데이터를 다시 불러오고 싶다면 아래처럼 쓸 수 있습니다.

function SearchResult({ keyword }) {
  useEffect(() => {
    console.log(`${keyword}로 다시 검색`);
  }, [keyword]);

  return <div>검색 결과</div>;
}

여기서 keyword가 바뀌면 effect도 다시 실행됩니다.

의존성 배열은 “이 값이 바뀌면 effect를 다시 실행해라”라고 React에 알려주는 목록입니다.
useEffect는 어디에 많이 쓰일까?
실전에서는 데이터 처리와 외부 연결 작업에서 가장 자주 나옵니다.

대표적으로 많이 나오는 예시는 아래와 같습니다.

1. API 호출
컴포넌트가 처음 열릴 때 서버에서 데이터를 가져오는 패턴입니다.
import { useEffect, useState } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('/api/users')
      .then((res) => res.json())
      .then((data) => setUsers(data));
  }, []);

  return <div>{users.length}명</div>;
}
2. 이벤트 리스너 등록
윈도우 resize, scroll 같은 외부 이벤트를 연결할 때 자주 씁니다.
useEffect(() => {
  const handleResize = () => {
    console.log(window.innerWidth);
  };

  window.addEventListener('resize', handleResize);

  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);
3. 타이머 / interval 처리
일정 시간마다 반복 실행해야 하는 로직도 useEffect 안에서 자주 처리합니다.
useEffect(() => {
  const timer = setInterval(() => {
    console.log('3초마다 실행');
  }, 3000);

  return () => clearInterval(timer);
}, []);
꼭 봐야 할 포인트
useEffect는 화면 그리기 자체보다 화면 바깥과 연결되는 작업에서 가장 많이 사용됩니다.
자주 막히는 포인트 / 문제해결
useEffect는 개념보다 실수 패턴을 알면 훨씬 빨리 익힙니다.
문제 1. 무한 렌더링
effect 안에서 state를 바꾸는데 의존성 배열을 잘못 잡으면 계속 다시 실행되는 문제가 생길 수 있습니다.
useEffect(() => {
  setCount(count + 1);
}, [count]);

이 코드는 count가 바뀔 때마다 effect가 다시 실행되고, 그 안에서 또 setCount를 호출하므로 반복될 수 있습니다.

문제 2. 의존성 배열을 빼먹음
effect 안에서 쓰는 값을 배열에 넣지 않으면 예상과 다른 타이밍에 동작하거나 오래된 값을 참조할 수 있습니다.
문제 3. cleanup을 안 함
이벤트 리스너, interval, subscription 같은 작업은 effect가 끝날 때 정리(cleanup)해야 중복 등록이나 메모리 누수를 막을 수 있습니다.
설정/이해 체크리스트
  • effect가 언제 실행돼야 하는지 먼저 말로 설명할 수 있는지 확인
  • effect 안에서 사용하는 값이 의존성 배열에 들어갔는지 확인
  • 이벤트 / 타이머 / 구독이 있다면 cleanup이 있는지 확인
  • state 변경이 effect 재실행을 계속 유발하지 않는지 확인
cleanup은 왜 중요한가?
useEffect를 "실행"만 보지 말고 "정리"까지 같이 이해해야 합니다.

useEffect는 return 함수로 cleanup 로직을 넣을 수 있습니다.

useEffect(() => {
  console.log('effect 시작');

  return () => {
    console.log('이전 effect 정리');
  };
}, [value]);

이 cleanup은 보통 아래 상황에서 중요합니다.

  • 컴포넌트가 사라질 때 정리해야 하는 이벤트
  • 반복 실행되는 interval 정리
  • 이전 요청/구독 상태 해제

즉 useEffect는 단순히 "실행" Hook이 아니라, 시작과 정리를 같이 다루는 Hook으로 이해하는 편이 더 정확합니다.

초보자가 꼭 체크할 포인트
  • useEffect는 렌더링을 직접 만드는 Hook이 아니라 렌더링 이후 부수 작업을 처리하는 Hook입니다.
  • 의존성 배열은 다시 실행될 조건을 정하는 목록입니다.
  • 빈 배열은 보통 처음 한 번 실행하려는 의도에서 사용합니다.
  • 이벤트 리스너나 interval은 cleanup까지 같이 써야 안전합니다.
FAQ
  • Q. useEffect는 왜 두 번 실행되는 것처럼 보이나요?
    → 개발 환경과 Strict Mode 설정에 따라 effect가 한 번 더 확인용으로 실행되는 것처럼 보일 수 있습니다. 무조건 배포 환경 문제라고 보진 말고 실행 환경을 같이 확인해야 합니다.
  • Q. 의존성 배열에 무엇을 넣어야 하나요?
    → effect 안에서 실제로 사용하는 값 중, 변경되면 다시 실행돼야 하는 값을 기준으로 생각하면 됩니다.
  • Q. API 호출은 무조건 useEffect에 넣어야 하나요?
    → 전통적인 패턴에서는 자주 그렇게 처리하지만, 상황에 따라 데이터 패칭 라이브러리나 서버 컴포넌트 구조를 함께 고려할 수도 있습니다.
결론
useEffect는 실행 시점보다 의존성 기준으로 이해하면 훨씬 쉬워집니다.

React의 useEffect는 처음 보면 어렵지만, 핵심은 의외로 단순합니다.

  • 렌더링 이후 실행해야 하는 작업을 넣고
  • 어떤 값이 바뀌면 다시 실행할지 정하고
  • 필요하면 cleanup으로 정리한다

이 흐름만 잡히면 useEffect는 훨씬 덜 어렵게 느껴집니다.

특히 useEffect를 잘 쓰려면 문법 자체보다 "언제 실행돼야 하는가"와 "무엇이 바뀌면 다시 실행돼야 하는가"를 먼저 말로 설명할 수 있어야 합니다.

useEffect는 렌더링 이후 부수 작업을 관리하는 Hook이고, 의존성 배열은 그 작업의 재실행 조건을 정하는 장치입니다.

※ 이 글은 React useEffect를 처음 이해하기 위한 입문 가이드입니다. 실제 프로젝트에서는 Strict Mode, 비동기 처리, 데이터 패칭 라이브러리, cleanup 전략까지 함께 보는 것이 좋습니다.

728x90
댓글
반응형
최근에 올라온 글
글 보관함
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30