수요일

React useEffect 무한루프 문제 해결하기

🔍 검색 키워드: React useEffect 무한루프, useEffect 의존성 배열, React hooks 성능 최적화, useEffect 콘솔 로그, 클로저 이슈

React useEffect 무한루프 문제 해결하기

useEffect는 강력하지만, 잘못 사용하면 무한 루프에 빠질 수 있습니다. 특히 의존성 배열이 없거나 잘못 설정되면 매번 렌더링 후에 effect가 실행되어 상태를 계속 변경하는 악순환에 빠집니다. 이 글에서는 증상부터 원인, 그리고 해결 방법까지 실제 코드로 설명하겠습니다.

1. 증상: 콘솔 로그가 무한정 출력된다

의존성 배열 없이 useEffect를 작성하면 다음과 같이 작동합니다.

useEffect(() => {
    console.log('effect 실행됨');
      setCount(count + 1);
      });

이 코드를 실행하면 콘솔에는:

  • effect 실행됨
  • effect 실행됨
  • effect 실행됨
  • (무한반복...)

이렇게 계속 출력되며, 브라우저가 느려지거나 먹통이 됩니다.

2. 원인 분석

의존성 배열이 없는 경우

useEffect(() => {
    setCount(count + 1); // 상태 변경
    }, []); // ❌ 의존성 배열 누락

의존성 배열을 생략하면 매번 렌더링 후마다 effect가 실행됩니다.

  1. 컴포넌트 렌더링
  2. useEffect 실행 → setCount 호출
  3. 상태 변경 → 컴포넌트 리렌더링
  4. useEffect 다시 실행
  5. 무한 반복...

의존성에 상태가 포함된 경우

useEffect(() => {
    setCount(count + 1);
    }, [count]); // ❌ count가 의존성에 포함됨

이 경우도 같은 문제가 발생합니다:

  1. count 변경 → effect 실행
  2. setCount(count + 1) → count 업데이트
  3. count 의존성이 변경됨 → effect 다시 실행
  4. 무한 루프...

3. 해결 방법

방법 1: 빈 의존성 배열 사용

마운트 시에만 한 번 실행하려면:

useEffect(() => {
    // API 호출, 리스너 등록 등
      fetchData();
      }, []); // ✅ 빈 배열: 마운트 시에만 실행

방법 2: 정확한 의존성 명시

실제 변경 감지할 항목만:

useEffect(() => {
    setDerivedValue(count * 2);
    }, [count]); // ✅ count 변경 시에만 effect 실행

방법 3: 상태 업데이트 함수 패턴

이전 상태에 기반해 업데이트:

useEffect(() => {
    setCount(prev => prev + 1);
    }, []); // ✅ 의존성 없이도 안전 (단, 무한루프 원하지 않으면 피하기)

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

함수가 의존성이 되는 경우:

const handleUpdate = useCallback(() => {
    setCount(count + 1);
    }, [count]);
    
    useEffect(() => {
      handleUpdate();
      }, [handleUpdate]); // 필요한 경우만 실행

방법 5: useRef로 초기 실행 방지

조건부 effect 실행:

const isFirstRender = useRef(true);
  
  useEffect(() => {
    if (isFirstRender.current) {
        isFirstRender.current = false;
            return;
              }
              
                setCount(count + 1); // 마운트 후에만 실행
                }, [count]);

4. 빠른 진단 가이드

증상 원인 해결책
무한 콘솔 로그 의존성 배열 누락 빈 배열 추가 []
특정 상태 변경 시 무한 루프 자신을 변경하는 상태가 의존성에 포함됨 의존성에서 제거하거나 함수 패턴 사용
마운트 후 특정 시점에만 실행 원함 조건 체크 없음 useRef 또는 상태 플래그로 조건 추가
객체/배열 의존성으로 매번 실행됨 새 객체/배열 매번 생성됨 useMemo 또는 상수로 변경

5. 실전 예제

API 호출 + cleanup 패턴 (무한루프 없음):

useEffect(() => {
    let isMounted = true;
    
      fetchUserData(userId).then(data => {
          if (isMounted) setUser(data);
            });
            
              return () => {
                  isMounted = false; // cleanup
                    };
                    }, [userId]); // userId 변경 시에만 새로 fetch

의존성 배열 체크

  • [] → 마운트 시에만 1회 실행
  • [dep1, dep2] → dep1 또는 dep2 변경 시 실행
  • 없음 → 매번 렌더링 후 실행 (⚠️ 위험)

useEffect의 무한루프는 React 개발에서 가장 흔한 실수입니다. 항상 의존성 배열을 명시하고, 그 안에는 실제 변경을 감지해야 할 항목만 넣으세요. 이 규칙만 지켜도 대부분의 성능 문제를 예방할 수 있습니다.

댓글 없음:

댓글 쓰기