src>extensions>React>cleanup12.mdx

[LOG] useEffect 클린업: 당신의 코드가 시한폭탄이 되지 않게 하는 법

v1.0.0
@young_log|React|Published on 2025-11-25

"회사 복지(?)로 사내세미나 한 내용이랍니다^^"

Details
Changelog
Dependencies

리액트 개발을 하며 가장 많이 사용하는 훅 중 하나가 useEffect이다. 하지만 많은 개발자가 부수 효과(Side Effect)를 만드는 데만 집중할 뿐, 그것을 정리하는 클린업(Cleanup)의 중요성은 간과하곤 한다. 결론부터 말하자면, 클린업 없는 이펙트는 언제 터질지 모르는 시한폭탄과 같다.

  • 오늘 다룰 핵심 주제
    • React 생명주기 중 “Cleanup”의 중요성
    • React의 StrictMode가 하는 역할
  • 목표
    • cleanup 또한 “선택”이 아닌 “필수”
    • <StrictMode />  “선택”이 아닌 “기본 습관”으로 인식

useEffect

리액트 컴포넌트가 렌더링될때마다 특정 작업을 수행할 수 있도록 설정할 수 있는 훅이다.

목적: DOM 조작, 데이터 패칭(API 호출), 구독(Subscription) 설정, 타이머 설정 등 렌더링 외의 작업을 수행

실행 시점은 렌더링 완료 후

여기서 핵심은 정리(Cleanup) 메커니즘 제공

useEffect 역할 : 새 인스턴스를 생성

Cleanup 의 역할 : 인스턴스를 정리하여 Side Effect를 해제

setInterval, addEventListener, new WebSocket() 등 새로운 부수 효과(Side Effect) 인스턴스를 메모리에 생성

클린업(Cleanup)이란?

  • useEffect의 return 함수가 Cleanup

: 클린업은 컴포넌트가 화면에서 사라지기 직전 (언마운트)이나, 의존성이 변경되어 useEffect가 재실행되기 직전에 이전에 생성했던 부수 효과(타이머, 리스너 등)를 제거하고 정리하는 작업을 의미

image.png

이미지가 안보이는 경우

노션 api를 사용하고 있어서 새로고침을 해야 될 수 있어요ㅜㅜ(60초마다 사라지는 중)

클린업(Cleanup) 필요 여부 구분

클린업(Cleanup) 필요 여부 구분해야 이를 적용할지 말지 알 수 있겠죠?

우리는 이 코드가 컴포넌트가 사라진 후에도 계속 실행되거나 남아있을 수 있는가? 를 고민하면 된답니다.

  • 남아있음 (Yes) → 클린업 필요 (return () => {} 작성)
  • 남아있지 않음 (No) → 클린업 불필요 (생략 가능)

image.png

Cleanup 적용 예시 코드

image.png

image.png

Cleanup 없는 이펙트가 위험한 이유

우리는 렌더링 이후 DOM 조작, 데이터 패칭, 구독 설정 등을 처리하기 위해 useEffect를 사용한다. 여기서 핵심은 **"인스턴스를 생성했다면, 반드시 해제해야 한다"**는 원칙이다.

클린업 함수는 컴포넌트가 언마운트되거나, 의존성이 변경되어 이펙트가 재실행되기 직전에 호출된다. 만약 이 과정을 누락할 경우 다음과 같은 문제가 발생한다.

  1. 중복 실행 오류: 이벤트 리스너가 제거되지 않고 중첩되어 동일한 이벤트가 여러 번 발동한다.
  2. 경쟁 조건(Race Condition): 이전 비동기 요청이 취소되지 않아 최신 데이터가 잘못된 응답으로 덮어씌워진다.
  3. 메모리 및 리소스 누수: 타이머나 웹소켓 연결이 해제되지 않고 쌓여 서버 부하를 일으키고 앱 성능을 저하시킨다.

문제가 터지는 유형은 아래와 같이 나눠볼 수 있는데,

즉시 문제가 터지는 경우 (예측 불가능한 동작)

  1. 같은 이벤트가 여러 번 실행됨: 중복 실행 오류
    1. 사용자가 페이지를 나갔다가 돌아올 때, 이전 이벤트 리스너가 제거되지 않아 인스턴스가 중첩되어 동작
  2. 타이머가 중복 실행: Side Effect가 중첩
    1. setInterval이나 setTimeout이 해제되지 않아 새로운 타이머와 함께 두 배속으로 동작하여 비정상 동작을 시작
  3. API 요청이 이중으로 발생: 경쟁 조건(Race Condition)을 유발
    1. 이전 요청이 취소되지 않고 남아있다가, 최신 요청의 응답보다 늦게 도착하여 잘못된 데이터로 상태를 덮어쓰거나 중복 호출을 일으킴

누적되어 쌓이다 터지는 경우 (시스템 안정성 붕괴)

  1. WebSocket 연결이 계속 쌓임: 리소스 누수
    1. WebSocket이나 Subscription 연결이 해제되지 않고 서버와 클라이언트 메모리에 잔류하며 서버 부하와 메모리 낭비를 일으킴
  2. 메모리 사용량이 점점 증가: 메모리 누수 (가장 치명적)
    1. 정리되지 않은 모든 잔여 Side Effect가 가비지 컬렉터(Garbage Collector)의 회수를 방해하여 메모리를 계속 점유한다. 이는 앱의 성능을 점진적으로 저하시킴

→ 결론: Cleanup 없는 Effect = 시한폭탄

당장 눈에 띄지 않더라도 사용자가 앱을 오래 머무를수록 이러한 잔여물은 앱을 마비시키는 잠재적 버그가 된다.


그래서 우리는 React에서 제공하는 개발 환경 전용 검증 도구

StrictMode를 사용하는 이유랍니다!

특징

  • 프로덕션 환경에는 영향 없음
  • 개발 중 잠재적인 문제를 의도적으로 드러냄
  • 이미 존재하는 버그를 사전에 발견 (사용자 신고 전 수정)

StrictMode 사용방법

image.png

  • Strict Mode는 <StrictMode> 컴포넌트 내부의 모든 컴포넌트 트리에 대해 검사를 활성화
  • 전체 앱에 대한 Strict Mode를 활성화하려면 렌더링할 때 루트 컴포넌트를 <StrictMode>로 래핑

StrictMode: 버그를 강제로 노출시키는 검증 장치

개발 환경에서 콘솔 로그가 두 번 찍히는 현상을 보고 불편함을 느끼는 경우가 있다. 하지만 이는 StrictMode가 제공하는 강력한 검증 시퀀스이다.

StrictMode는 개발 모드에서만 작동하는 도구로, 잠재적인 사이드 이펙트 문제를 의도적으로 드러낸다. 구체적으로는 다음과 같은 메커니즘을 수행한다.

  • 의도적인 이중 렌더링: 컴포넌트가 순수한지, 예측 가능한 로직을 가졌는지 확인한다.
  • 이펙트 재실행 (Mount -> Unmount -> Mount): 클린업 로직이 제대로 작성되었는지 확인하기 위해 강제로 이펙트를 껐다 켜는 과정을 거친다.

이 과정을 통해 개발자는 사용자가 버그를 발견하기 전에 개발 단계에서 문제를 사전에 진단하고 수정할 수 있다.

다음은 StrictMode가 검사하는 내용입니다.

Strict Mode는 다음과 같은 개발 전용 동작을 활성화합니다.

  • 컴포넌트가 순수하지 않은 렌더링으로 인한 버그를 찾기 위해 추가로 다시 렌더링합니다.
  • 컴포넌트가 Effect 클린업이 누락되어 발생한 버그를 찾기 위해 Effect를 다시 실행합니다.
  • 컴포넌트가 Ref 클린업이 누락되어 발생한 버그를 찾기 위해 Ref 콜백을 다시 실행합니다.
  • 컴포넌트가 더 이상 사용되지 않는 API를 사용하는지 확인합니다.

→ 핵심은 잠재적인 Side Effect와 레거시 사용을 막는 것

Strict Mode의 동작

  1. 이중 렌더링
    1. React는 컴포넌트 본문 및 useEffect 로직을 의도적으로 두 번 실행
      1. 순수성 검사: 렌더링 로직이 순수한지 확인합니다.
      2. 클린업 검사: useEffect의 Cleanup 로직이 제대로 작동하는지 강제로 테스트합니다.
  2. 레거시 API 감지
    1. 지원이 종료될 예정이거나 비동기 환경에서 문제를 일으킬 수 있는 코드를 사용하는지 확인하고, 단순히 콘솔에 경고 메시지를 출력
    2. React는 컴포넌트가 렌더링되거나 실행될 때, 코드 내부에서 findDOMNodecomponentWillMount 같은 레거시 함수나 메서드가 호출되는 것을 감지

image.png

  • 불완전한 렌더링으로 인한 버그를 찾기 위해 컴포넌트가 한 번 더 재렌더링함.
  • Effect cleanup이 누락되어 발생한 버그를 찾기 위해 컴포넌트가 Effects를 한 번 더 재실행함.

StrictMode 클린업 습관의 FE/BE 협업 이점

1. 프론트엔드 (FE) 안정성 확보

  • 디버깅 난이도 하락
  • 성능 유지

2. 백엔드 (BE) 및 서버 부하 감소

  • 불필요한 API 요청 감소
  • 네트워크 리소스 절약
  • 서버 안정화

→ FE의 cleanup 습관이 BE의 안정성과 직결됨

클린업 습관이 가져오는 개발 윤리

클린업을 철저히 관리하는 습관은 단순히 프론트엔드의 안정성에만 그치지 않는다. 불필요한 API 요청을 방지함으로써 네트워크 리소스를 절약하고 백엔드 서버의 안정성까지 기여할 수 있다.

결국 StrictMode를 활용해 클린업 로직을 검증하는 습관은 앱의 성능과 안정성을 지키는 가장 기본적인 개발 윤리인 셈이다.

기타

그리고 이건 내가 개인적으로 궁금했던 부분이라 더 공부한 내용이다.

Strict Mode와 “use Strict” 차이

image.png

인스턴스 중복 생성 구조

개념 요약

  • Effect는 “새 인스턴스 생성 역할”
  • Cleanup은 “이전 인스턴스 제거 역할”

Cleanup 누락 시

  • 인스턴스가 계속 누적됨
  • 상태 충돌 발생
  • 비정상 동작 시작

한 줄 정리

→ Cleanup 없는 Effect = 시한폭탄

EOF (End of File)

내가 담당하는 프로젝트에서도 타이머와 이벤트 리스너의 클린업 여부에 따라 앱의 신뢰도가 달라지는 것을 체감하고 있다. 평범한 디자인을 넘어 완성도 높은 코드를 지향한다면, 지금 당장 자신의 프로젝트에 StrictMode를 켜고 숨겨진 시한폭탄을 점검해 보아야 한다.

Happy Coding & Cleanup!

TERMINAL
DEBUG CONSOLE
OUTPUT
~/stay-young-loggit(main)npm run comment:write
nickname:
content:
-- TOTAL COMMENTS: 0 --
[LOADING...] fetching data from supabase...