useEffect 멈춰!

gangmin·2025년 6월 1일
16

React

목록 보기
3/5
post-thumbnail

☠️ useEffect, 남용하면 독

React를 쓰다 보면 거의 반사적으로 useEffect를 사용하게 됩니다. 데이터 가져오기, 상태 동기화, DOM 조작… 어떤 이유에서든 useEffect를 쓰고 있지만, 정말 지금 이 순간 useEffect가 필요한 걸까요?

이 글에서는 useEffect를 과용했을 때 생기는 문제와 정말로 필요한 순간, 그리고 대체할 수 있는 다른 React 훅들을 정리합니다. 🤓

🤔 왜 useEffect 남용이 문제일까?

1. 렌더링과 무관한 부수효과

많은 경우 useEffect는 단순히 어떤 값을 계산하거나 상태를 업데이트하는 데 사용됩니다. 하지만 이는 React의 "렌더링 → DOM 반영 → 이펙트 실행" 순서를 고려하지 않은 접근입니다. 불필요한 이펙트 실행은 컴포넌트 렌더링 타이밍을 예측하기 어렵게 만들고, 성능을 떨어뜨립니다.

// ❌ 잘못된 예시
useEffect(() => {
  const result = expensiveCalculation(input);
  setResult(result);
}, [input]);

위 코드는 input이 바뀔 때마다 expensiveCalculation을 수행하고 상태를 업데이트합니다. 하지만 이건 사실 useMemo로 처리할 수 있는 계산입니다.

// ✅ 올바른 예시
const result = useMemo(() => expensiveCalculation(input), [input]);

렌더링 도중 실행돼야 할 계산은 useMemo, 부수 효과(side effect)는 useEffect. 이 두 역할을 구분해야 합니다.

🚫 흔한 useEffect 안티패턴

1. derived state (파생된 상태)를 useEffect로 만드는 경우

const [count, setCount] = useState(0);
const [double, setDouble] = useState(0);

useEffect(() => {
  setDouble(count * 2);
}, [count]);

double은 오직 count로부터 계산될 수 있는 값이기 때문에 굳이 별도로 상태로 관리할 이유가 없습니다. 이렇게 다른 상태에 전적으로 의존해서 파생되는 값은 useMemo나 그냥 렌더링 안에서 직접 계산하는 것이 훨씬 명확하고 효율적입니다.

// ✅ 더 나은 방식
const double = useMemo(() => count * 2, [count]);
// 또는 그냥 const double = count * 2; 도 충분함

=> 상태는 "사용자가 직접 바꿀 수 있는 값"에만 써야 의미가 있습니다.

2. 초기값 세팅도 useEffect로?

const [user, setUser] = useState(null);

useEffect(() => {
  setUser(defaultUser);
}, []);

useEffect 없이도 초기값은 직접 줄 수 있습니다.

const [user, setUser] = useState(defaultUser);

✅ useEffect는 언제 써야 할까?

진짜 필요한 경우는 다음과 같습니다.

상황예시
외부 API 호출fetch, axios 등 비동기 데이터 가져오기
이벤트 리스너 등록/해제window.addEventListener, document.addEventListener
타이머 설정setTimeout, setInterval
외부 라이브러리 연동지도, 차트, 3rd-party 라이브러리 연결
상태 → 외부 동기화localStorage, URL, document.title 등 브라우저에 반영

이 모든 공통점은 "렌더링 결과와 무관한 외부 동작"입니다. React의 렌더링 "흐름" 안에서는 일어날 수 없는 일이라는 뜻입니다.

1. 렌더링과 외부 동작은 분리된다

React는 렌더링 → DOM 반영 → effect 실행이라는 순서를 따릅니다.

  • useMemo, useState, useCallback 등은 렌더 중에 동작하고,
  • useEffect는 렌더링 이후, 즉 DOM까지 그려지고 난 "후처리 단계"에서 동작합니다.

즉, useEffect는 React 입장에서 말하면 "렌더링에는 직접 관여할 수 없는 시점에 실행되는 동작"이에요.

🔄 훅 제대로 사용하기

간단히 정리하면,

목적 적절한 훅
렌더 중 계산(파생값) useMemo
함수 캐싱useCallback
외부 동작useEffect
상태 저장useState
DOM 접근useRef + useEffect

💡 정리

React에서 useEffect는 사이드 이펙트를 위한 훅입니다. 계산, 값 추론, 상태 파생 등은 React의 렌더링 흐름 안에서 처리되어야 하고, useEffect는 렌더링 외부의 일을 수행할 때만 사용해야 합니다.

📌 렌더링 중 처리 가능한 일은 useEffect로 미루지 마세요.
useEffect는 필요한 순간에만, 단호하게 써야 합니다. 😎

2개의 댓글

comment-user-thumbnail
2025년 6월 1일

좋은 글이네요!!

답글 달기
comment-user-thumbnail
2025년 6월 15일

정답이 너무나 명확한 문제입니다
https://react.dev/learn/you-might-not-need-an-effect

They let you “step outside” of React and synchronize your components with some external system like a non-React widget, network, or the browser DOM.

언제 어떻게 써야하는지 아예 정해져있어요

답글 달기