devlog.

useEffect 완전 정복: 의존성 배열과 클린업 함수

·7분 읽기

useEffect란?#

useEffect는 React 함수형 컴포넌트에서 사이드 이펙트(side effect)를 처리하기 위한 훅입니다. 사이드 이펙트란 컴포넌트 렌더링 이외에 발생하는 작업을 말합니다 — 데이터 페칭, 이벤트 리스너 등록, DOM 조작 등이 여기에 해당합니다.

import { useEffect, useState } from 'react'

function UserProfile({ userId }: { userId: string }) {
  const [user, setUser] = useState(null)

  useEffect(() => {
    // 사이드 이펙트: API 호출
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data))
  }, [userId]) // userId가 변경될 때마다 실행

  return <div>{user?.name}</div>
}

의존성 배열의 동작 원리#

useEffect의 두 번째 인자인 의존성 배열은 이펙트가 언제 실행될지를 결정합니다.

세 가지 패턴#

1. 의존성 배열 없음 — 매 렌더링마다 실행

useEffect(() => {
  console.log('매 렌더링마다 실행됩니다')
})

2. 빈 배열 — 마운트 시 한 번만 실행

useEffect(() => {
  console.log('컴포넌트가 마운트될 때 한 번만 실행됩니다')
}, [])

3. 값이 있는 배열 — 해당 값이 변경될 때 실행

useEffect(() => {
  console.log(`count가 ${count}로 변경되었습니다`)
}, [count])

클린업 함수#

클린업 함수는 useEffect 내에서 반환하는 함수로, 컴포넌트가 언마운트되거나 다음 이펙트가 실행되기 전에 호출됩니다.

useEffect(() => {
  // 이벤트 리스너 등록
  const handleResize = () => {
    console.log('창 크기:', window.innerWidth)
  }
  window.addEventListener('resize', handleResize)

  // 클린업: 이벤트 리스너 제거
  return () => {
    window.removeEventListener('resize', handleResize)
  }
}, [])

흔한 실수와 해결책#

무한 루프 문제#

// ❌ 잘못된 예: 객체를 의존성으로 사용
function BadExample() {
  const options = { page: 1 } // 매 렌더링마다 새 객체 생성

  useEffect(() => {
    fetchData(options) // options는 항상 새 참조 → 무한 루프
  }, [options])
}

// ✅ 올바른 예: 원시값을 의존성으로 사용
function GoodExample() {
  const page = 1

  useEffect(() => {
    fetchData({ page })
  }, [page]) // 원시값은 참조가 동일
}

비동기 함수 사용#

// ❌ useEffect 콜백을 직접 async로 만들면 안 됨
useEffect(async () => {
  const data = await fetchData() // 이렇게 하면 안 됩니다
}, [])

// ✅ 내부에서 async 함수 선언 후 호출
useEffect(() => {
  async function loadData() {
    const data = await fetchData()
    setData(data)
  }

  loadData()
}, [])

React 18의 Strict Mode와 useEffect#

React 18의 Strict Mode에서는 개발 환경에서 useEffect가 두 번 실행됩니다. 이는 의도적인 동작으로, 클린업 함수가 올바르게 구현되었는지 확인하기 위해서입니다. 프로덕션 환경에서는 한 번만 실행됩니다.

관련 포스트