Frontend/React

React useEffect 완벽 가이드: 의존성 배열부터 오용 방지까지

sliver__ 2025. 7. 24. 04:19
728x90

useEffect는 React에서 가장 많이 사용되는 훅 중 하나지만, 동시에 가장 혼란스럽기도 합니다.
특히 의존성 배열을 언제, 어떻게 설정해야 하는지 헷갈려서 불필요한 렌더링이나 버그가 발생하는 경우도 많습니다.

이번 글에서는 useEffect의 정확한 사용법과 의존성 배열 설정의 규칙, 그리고 자주 하는 실수와 대처법까지 자세히 알아보겠습니다.


useEffect 의존성 배열의 기본 규칙

규칙 1: 모든 state, props, context 값은 의존성에 포함해야 함

useEffect(() => {
  console.log(value);  
}, [value]);  // value는 state 혹은 prop이라면 반드시 포함!
  • 상태(state)나 props가 effect 안에서 사용되면 반드시 의존성 배열에 포함해야 합니다.
  • 구독 중인 Context 값도 동일하게 포함해야 합니다.

✅ 규칙 2: "반응형 값(reactive values)"도 포함해야 함

reactive value란 다음 중 하나입니다:

  • 상태(state)
  • props
  • context
  • 위 요소들을 참조하는 함수나 변수

예를 들어:

 
const durationText = `${minutes}:${seconds}`;

minutes, seconds가 state라면, durationText도 의존성으로 포함해야 합니다.


✅ 규칙 3: 객체나 배열은 의존성으로 넣지 말 것

useEffect(() => {
  // do something with obj
}, [obj]);  // 안됨!
  • JavaScript에서 객체는 렌더링마다 새로운 참조를 가지므로, 내용이 같아도 매번 다른 값으로 인식되어 effect가 반복 실행됩니다.

그렇다면, 객체나 함수를 사용해야 할 때는?

방법 1: 객체의 필요한 속성만 분리해서 포함

 
useEffect(() => {
  console.log(user.id);  
}, [user.id]);

 

방법 2: 함수는 useCallback으로 메모이제이션

const handleClick = useCallback(() => {
  // do something
}, [dependency]);

useEffect(() => {
  handleClick();
}, [handleClick]);  // 안정적인 함수 참조 유지

자주 발생하는 useEffect 오용 사례 3가지

1. 사용자 이벤트 처리에 useEffect 사용

 
// 클릭 이벤트 처리를 useEffect로 처리하면 부자연스럽고 비효율적
useEffect(() => {
  if (clicked) alert('Clicked!');
}, [clicked]);

2. 마운트 시 API 호출

// 가능은 하지만 큰 앱에서는 React Query 등 전문 도구 사용 추천
useEffect(() => {
  fetchData();
}, []);

3. state를 감지하여 다른 state를 업데이트

// ❌ 의존 관계가 많아지고 리렌더링이 복잡해짐
useEffect(() => {
  if (count > 5) setStatus('Done');
}, [count]);
=> 가능한 경우 파생 상태(derived state)로 처리하세요.
 
const status = count > 5 ? 'Done' : 'In Progress';

기타 팁과 전략

  • setState 함수는 의존성 배열에 넣을 필요 없음
    → React가 동일 참조를 보장해 줍니다.
  • 헬퍼 함수는 effect 내부로 옮기거나, 컴포넌트 밖으로 분리하면 의존성에서 제거 가능
  • 의존성이 많은 경우 useReducer로 리팩토링 고려

결론: useEffect는 "마지막 수단"으로 생각하자

React 공식 문서에서도 useEffect를 "escape hatch"라고 표현합니다.
즉, 정말 필요한 경우가 아니면 다른 방식으로 처리하는 것이 권장됩니다.

이런 순서로 접근하세요:

  1. 이벤트 핸들러로 해결 가능한가?
  2. 파생 상태로 표현할 수 있는가?
  3. 불가피하다면, useEffect 사용

요약

상황사용 여부대안
데이터 로딩 사용 가능 (소형 앱) React Query 등
클릭 처리 X 이벤트 핸들러
state → state X 파생 상태
외부 라이브러리 사용 O 필수
DOM 직접 접근 O 필수
728x90