React – 상태 관리와 Hooks – 기본 Hooks – 1 – useEffect의 의존성 배열과 정리(clean-up)

React – 상태 관리와 Hooks – 기본 Hooks – 1 – useEffect의 의존성 배열과 정리(clean-up)

React – 상태 관리와 Hooks – 기본 Hooks – 1 – useEffect의 의존성 배열과 정리(clean-up)

안녕하세요 여러분! 😊
이번 시간에는 **React의 대표적인 훅 중 하나인 useEffect**에 대해 알아보겠습니다.
이 훅은 말 그대로 컴포넌트에서 “효과(effect)”, 즉 렌더링 이외의 작업을 처리할 수 있게 해주는 친구예요.

예를 들면, API 호출, 이벤트 리스너 등록, 타이머 설정 등과 같은 작업을 useEffect 안에서 처리하게 됩니다.
하지만 useEffect언제 실행되느냐, 어떻게 정리되느냐에 따라 동작이 완전히 달라지기 때문에
의존성 배열(dependency array)정리(clean-up) 개념을 꼭 함께 이해해야 해요!


1. useEffect란 무엇인가요?

useEffect는 컴포넌트가 렌더링된 후 특정 작업을 수행하도록 설정하는 훅이에요.

import { useEffect } from 'react';

useEffect(() => {
  // 이 안에서 side effect 발생!
});

🧠 비유하자면?

useEffect는 마치 “집 청소 후 커피 한잔 하는 것” 같아요.
뭔가 주 업무(렌더링)가 끝난 후에 추가로 처리하고 싶은 일을 맡기는 거예요!


2. 기본 사용 예시

useEffect(() => {
  console.log('컴포넌트가 렌더링될 때마다 실행됨');
});

이렇게 쓰면 모든 렌더링 이후에 항상 실행됩니다.
즉, setState로 상태가 바뀌어서 리렌더링이 발생할 때마다 계속 실행돼요.


3. 의존성 배열 (Dependency Array)

useEffect의 두 번째 인자로 배열을 넣으면, 해당 값이 변경될 때만 effect가 실행됩니다.

예시 1: 처음 한 번만 실행 (Mount 시)

useEffect(() => {
  console.log('처음 한 번만 실행됨!');
}, []);
  • 의존성 배열이 []이면 컴포넌트가 처음 마운트될 때 딱 한 번만 실행돼요.
  • 마치 componentDidMount 같은 역할!

예시 2: 특정 값이 바뀔 때만 실행

useEffect(() => {
  console.log('카운트가 바뀌었습니다:', count);
}, [count]);
  • count가 바뀔 때만 실행됩니다.
  • 이전과 현재 값을 비교해 변경되었을 때만 반응해요.

4. Clean-up 함수란?

useEffect컴포넌트가 사라질 때나 effect가 다시 실행되기 전정리(clean-up) 함수를 호출할 수 있어요.

사용 예시

useEffect(() => {
  const timer = setInterval(() => {
    console.log('타이머 동작 중...');
  }, 1000);

  return () => {
    clearInterval(timer);
    console.log('타이머 정리됨');
  };
}, []);
  • 마운트 시 타이머 시작
  • 언마운트 시 정리(clean-up) 실행

🧹 정리 함수는 마치 퇴근 전에 사무실 불 끄고 나가는 느낌이에요!


5. 정리 함수가 필요한 이유

  1. 메모리 누수 방지
    이벤트 리스너, 타이머, API 스트림 등은 사용 후 반드시 정리해야 해요.

  2. 정확한 동작 보장
    오래된 effect가 남아있으면 예상치 못한 결과가 발생할 수 있어요.

  3. 클로저 문제 방지
    오래된 상태에 접근하는 문제를 방지하기 위해 최신 값을 반영하려면 정리 후 다시 effect를 적용해야 해요.


6. 실전 예제: 윈도우 리사이즈 이벤트 등록

function WindowSizeLogger() {
  useEffect(() => {
    const logSize = () => {
      console.log(`현재 창 크기: ${window.innerWidth}px`);
    };

    window.addEventListener('resize', logSize);

    // 정리 함수
    return () => {
      window.removeEventListener('resize', logSize);
      console.log('리스너 정리 완료!');
    };
  }, []);

  return <div>창 크기를 바꿔보세요!</div>;
}
  • 리사이즈 이벤트를 등록했다면, 컴포넌트가 사라질 때 꼭 제거해야 합니다.
  • 그렇지 않으면 불필요한 이벤트가 계속 남아서 성능 저하가 생겨요.

7. 의존성 배열 관리 팁

상황 의존성 배열
항상 실행하고 싶다 없음
처음 한 번만 실행 []
특정 값이 바뀔 때 실행 [값1, 값2] 등 포함
함수를 의존성에 넣을 때 useCallback으로 메모이제이션 필요

🔍 의존성 배열이 비었는데 내부에서 사용하는 변수나 함수가 있으면 의존성 누락 경고가 뜰 수 있어요.
이럴 땐 ESLint가 도와주기도 하니 참고해주세요!


8. 자주 하는 실수

실수 예시 해결 방법
의존성 누락 useEffect(() => { fetchData(); }, []) → fetchData는 외부 함수인데 의존성 없음 useCallback 또는 의존성 배열에 포함
정리 함수 누락 이벤트 등록했는데 제거 안 함 return () => {...} 작성
내부에서 상태 변경 무한 루프 useEffect(() => { setValue(count + 1); }, [count]) 조건문 또는 플래그로 제어 필요

9. 한눈에 정리 – useEffect 패턴

패턴 설명
useEffect(() => {...}) 모든 렌더링 이후 실행
useEffect(() => {...}, []) 마운트 시 한 번만 실행
useEffect(() => {...}, [val]) val이 바뀔 때마다 실행
useEffect(() => {...; return () => {...}; }, [...]) 실행 전에 항상 정리하고 새 effect 적용

마무리하며

useEffectReact에서 side effect를 제어하는 가장 핵심적인 도구입니다.
정확히 동작 시점을 컨트롤하고, 불필요한 자원을 제거하는 습관을 들이면 성능 최적화와 버그 방지에 큰 도움이 돼요!

🔥 핵심 요약!

useEffect = 사이드 이펙트 + 타이밍 조절 + 정리까지 책임지는 슈퍼 도우미

이제부터는 데이터를 불러오거나, 이벤트를 연결하거나, 타이머를 다룰 때
무조건 useEffect를 먼저 떠올려 보세요!

다음 시간에는 useEffect와 함께 자주 쓰이는 또 다른 훅, useMemo, useCallback 등을 통해
성능 최적화까지 살펴볼게요! 🚀

답글 남기기