누구나 로고
온라인 강의기업·단체교육읽는 강의트렌드 인사이트무료 강의공지사항문의하기채용 사이트
모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.
로그인무료 회원가입
강좌리액트 입문 — 컴포넌트로 만드는 웹11강

11강 / 전체 28강

useEffect 기초

6분 읽기 조회 0

useEffect의 동작 원리와 실행 시점, 의존성 배열의 역할, 클린업 함수가 왜 필요한지를 구체적인 예시로 깊이 이해합니다.

🔄 사이드 이펙트란 무엇인가

리액트 컴포넌트의 주된 역할은 데이터(state, props)를 받아 JSX를 반환하는 것입니다. 그런데 실제 앱에서는 컴포넌트가 렌더링 이외의 작업도 해야 합니다. 예를 들면:

  • 서버에서 데이터 가져오기 (fetch API, axios)
  • DOM 직접 조작 (스크롤 위치, 포커스)
  • 타이머 설정 (setTimeout, setInterval)
  • 이벤트 리스너 등록/해제
  • 로컬 스토리지 읽기/쓰기

이처럼 렌더링과 관계없이 "외부 세계"와 상호작용하는 코드를 사이드 이펙트(Side Effect)라고 합니다. useEffect는 이런 사이드 이펙트를 안전하게 처리하기 위한 훅입니다.

⚙️ useEffect 기본 문법과 실행 시점

import { useEffect, useState } from 'react'

function Timer() {
  const [seconds, setSeconds] = useState(0)

  useEffect(() => {
    console.log('이 코드는 렌더링 후 실행됩니다')
  })

  return <p>{seconds}초</p>
}

useEffect는 컴포넌트가 렌더링된 이후에 실행됩니다. 첫 번째 인수는 실행할 함수(이펙트 함수), 두 번째 인수는 의존성 배열입니다.

📦 의존성 배열 — 세 가지 형태

의존성 배열([])이 언제 실행될지를 제어합니다:

// 1. 배열 없음 — 매 렌더마다 실행 (거의 사용 안 함)
useEffect(() => {
  console.log('매번 실행')
})

// 2. 빈 배열 — 마운트 시 한 번만 실행
useEffect(() => {
  console.log('컴포넌트가 처음 화면에 나타날 때만 실행')
  // API 호출, 이벤트 리스너 등록 등
}, [])

// 3. 값이 있는 배열 — 그 값이 바뀔 때마다 실행
useEffect(() => {
  console.log(`userId가 ${userId}로 바뀌었을 때 실행`)
  // userId에 해당하는 데이터 재패치
}, [userId])

의존성 배열에 있는 값이 이전 렌더의 값과 다를 때 이펙트가 다시 실행됩니다. []는 의존성이 없으니 처음 한 번만 실행됩니다.

🧹 클린업 함수 — 뒷정리

이펙트 함수에서 함수를 반환하면, 그것이 클린업(cleanup) 함수입니다. 컴포넌트가 언마운트되거나 이펙트가 다시 실행되기 직전에 호출됩니다. 이것이 없으면 메모리 누수(memory leak)가 발생합니다.

function Stopwatch() {
  const [time, setTime] = useState(0)
  const [running, setRunning] = useState(false)

  useEffect(() => {
    if (!running) return

    const interval = setInterval(() => {
      setTime((prev) => prev + 1)
    }, 1000)

    // 클린업: 다음 이펙트 실행 전 또는 언마운트 시 인터벌 제거
    return () => {
      clearInterval(interval)
    }
  }, [running])  // running이 바뀔 때마다 실행

  return (
    <div>
      <p>{time}초</p>
      <button onClick={() => setRunning(!running)}>{running ? '정지' : '시작'}</button>
    </div>
  )
}

클린업이 없다면 running이 바뀔 때마다 새 인터벌이 추가되어 시간이 빠르게 흐르고, 컴포넌트가 제거된 후에도 인터벌이 계속 동작합니다.

🌐 데이터 패칭과 useEffect

가장 흔한 useEffect 사용 사례는 데이터 패칭입니다:

interface Post { id: number; title: string; body: string }

function PostDetail({ postId }: { postId: number }) {
  const [post, setPost] = useState<Post | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setLoading(true)
    setError(null)

    fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`)
      .then((res) => {
        if (!res.ok) throw new Error('서버 오류')
        return res.json()
      })
      .then((data: Post) => setPost(data))
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false))
  }, [postId])  // postId가 바뀔 때마다 재패치

  if (loading) return <div>불러오는 중...</div>
  if (error) return <div>오류: {error}</div>
  if (!post) return null

  return (
    <article>
      <h2>{post.title}</h2>
      <p>{post.body}</p>
    </article>
  )
}

⚠️ 흔한 실수 — 무한 루프

객체나 배열을 의존성 배열에 넣으면 무한 루프가 발생할 수 있습니다. 렌더마다 새 객체/배열이 생성되고, 참조가 다르다고 판단해 이펙트를 계속 실행합니다.

// ❌ 매 렌더마다 새 객체 → 무한 루프
useEffect(() => {
  fetchData(options)
}, [{ page: 1, limit: 10 }])  // 매번 새 객체 참조!

// ✅ 원시값을 의존성으로
useEffect(() => {
  fetchData({ page, limit })
}, [page, limit])

✅ 정리

  • useEffect는 렌더링 이후 사이드 이펙트를 처리합니다.
  • 의존성 배열: 없음(매 렌더) / [](마운트 1회) / [값](값 변경 시).
  • 클린업 함수로 타이머·이벤트 리스너를 해제해 메모리 누수를 방지합니다.
  • 객체/배열을 의존성으로 넣으면 무한 루프 — 원시값으로 분해해서 넣으세요.

관련 주제

  • useEffect 훅
  • 의존성 배열
  • 마운트 업데이트 시점
  • 클린업 함수
  • 사이드 이펙트
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 리액트 입문 — 컴포넌트로 만드는 웹
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나
이전 10강폼 다루기다음 12강 데이터 가져오기(fetch)

댓글

0/1000

불러오는 중...

목차

  1. 1.리액트란 무엇인가
  2. 2.개발 환경 만들기 — Vite
  3. 3.JSX 기초
  4. 4.컴포넌트 만들기
  5. 5.Props로 데이터 전달
  6. 6.State와 useState
  7. 7.이벤트 처리
  8. 8.조건부 렌더링
  9. 9.리스트 렌더링과 key
  10. 10.폼 다루기
  11. 11.useEffect 기초
  12. 12.데이터 가져오기(fetch)
  13. 13.상태 끌어올리기
  14. 14.컴포넌트 합성과 재사용
  15. 15.useRef와 DOM 접근
  16. 16.커스텀 훅 만들기
  17. 17.Context API
  18. 18.useReducer
  19. 19.리스트 앱 실전 ①
  20. 20.리스트 앱 실전 ②
  21. 21.라우팅 — React Router
  22. 22.스타일링 방법들
  23. 23.리스트·상세 페이지 연결
  24. 24.비동기 상태 관리 패턴
  25. 25.성능 기초 — memo
  26. 26.에러 처리와 경계
  27. 27.환경변수와 빌드
  28. 28.배포하기

고객지원

  • 공지사항
  • 자주 묻는 질문
  • 문의하기
  • 커뮤니티

이용안내

  • 이용약관
  • 개인정보처리방침
  • 환불정책

서비스

  • 회사소개
  • 회원가입
  • 신규 강의
  • 무료 강의
누구나 로고
이용약관개인정보처리방침환불정책

상호명: NUGUNA  |  대표자: 정우진  |  사업자등록번호: 392-32-01817  |  통신판매업신고: 제 2026-서울양천-0564 호

주소: 서울특별시 양천구 목동서로 100  |  이메일: nugunapass@gmail.com  |  전화: 010-6395-3043

© 2026 NUGUNA. All rights reserved.

KB예금주인증관리자
홈강의읽는 강의문의하기MY