고양이hyebin
[React] useEffect의 Cleanup, 이제 함수 대신 객체를 쓴다고?
[React] useEffect의 Cleanup, 이제 함수 대신 객체를 쓴다고?
June 15, 2026

최근 RFC 278이라는 재미있는 제안이 올라왔습니다.

React로 개발하다 보면 useEffect 안에서 return () => { ... }로 정리 함수를 짜는 게 익숙할텐데요,

하지만 위 PR의 요점은 이제 cleanup함수를 직접 반환하지 말고, [Symbol.dispose]라는 메서드를 가진 객체를 반환하자는 겁니다. 처음엔 "굳이?" 싶었는데, 내용을 뜯어보니 재미있는 이유가 있었습니다. 👀


[Symbol.dispose]가 도대체 뭔데?

"이 객체가 자원을 다 썼을 때, 스스로 어떻게 정리해야 하는지 적어둔 매뉴얼"입니다.

JavaScript에 최근 'Explicit Resource Management'라는 스펙이 들어오면서 using이라는 키워드가 생겼습니다. 쉽게 말해, 개발자가 일일이 removeEventListenerclearInterval을 부르지 않아도, 스코프가 끝나면 알아서 정리되도록 만드는 장치입니다.

실제 작동 방식을 코드로 볼까요?

class DatabaseConnection {
  constructor(name) {
    this.name = name;
    console.log(`${this.name} 연결 성공!`);
  }

  // 자원 해제 매뉴얼
  [Symbol.dispose]() {
    console.log(`${this.name} 연결 종료 중...`);
  }
}

function processData() {
  console.log("데이터 처리 시작");
  
  // using을 통해 블록 스코프가 끝나면 자동으로 연결 종료
  using db = new DatabaseConnection("UserDB");
  
  console.log("DB 작업 수행 중...");
}

processData(); 
// 출력 순서:
// 1. 데이터 처리 시작
// 2. UserDB 연결 성공!
// 3. DB 작업 수행 중...
// 4. UserDB 연결 종료 중... (<- 블록을 벗어나는 순간 자동 호출!)

이 코드가 작동하는 원리는 다음과 같습니다.

  1. 1.약속: JavaScript는 모든 객체에게 이렇게 약속했습니다. "만약 네가 자원을 정리해야 한다면, [Symbol.dispose]라는 이름의 메서드를 만들어서 그 안에 정리 로직을 담아둬."
  2. 2.using의 역할: 개발자가 using 키워드로 변수를 선언하면, JS 엔진은 그 변수가 정의된 블록({ })을 벗어나는 순간 딱 한 가지만 체크합니다. "너한테 [Symbol.dispose]라는 메서드가 있어?"
  3. 3.자동 실행: 만약 있다면, 엔진이 그 메서드를 자동으로 호출해줍니다.

즉, [Symbol.dispose]는 단순히 정리하는 함수가 아니라, "나를 정리하는 방법은 여기 적혀있어"라고 엔진에게 건네주는 규격화된 인터페이스인 셈입니다.

왜 React가 이 흐름을 타려는 걸까

기존에는 React가 정해준 방식(() => {})으로만 정리해야 했습니다. 하지만 Symbol.dispose는 JavaScript 표준이기 때문에, 앞으로 더 많은 라이브러리와 브라우저 내장 API들이 이 규격을 따를 것으로 예상됩니다. React가 미리 이걸 지원해두면, 나중에 그런 객체들을 별도 변환 없이 useEffect에서 바로 return할 수 있게 되는 거죠.

기존 (함수 방식):

useEffect(() => {
  const timer = setInterval(() => console.log('Hi'), 1000);
  return () => clearInterval(timer); // 정리 로직이 함수 내부에 숨음
}, []);

제안 (객체 방식):

useEffect(() => {
  const timer = setInterval(() => console.log('Hi'), 1000);
  return {
    [Symbol.dispose]() {  // "나를 버릴 땐 이 메서드를 써"라고 명시
      clearInterval(timer);
    }
  };
}, []);

그래서 당장 써야 할까?

아뇨, 아직 논의 중인 제안(RFC)일 뿐입니다. 정식으로 React에 들어올지, 들어온다면 언제일지도 모릅니다.

하지만 JavaScript에서 using 문법과 [Symbol.dispose] 는 TypeScript 5.2+부터 공식 지원을 시작했습니다.

  • Babel 플러그인(@babel/plugin-proposal-explicit-resource-management)을 사용하면 지금 바로 트랜스파일하여 활용할 수 있습니다.

즉, React의 useEffect에서 이 기능을 쓰는 건 아직 기다려야 하지만, JavaScript에서 using 문법과 Disposable 패턴 자체는 사용이 가능합니다

다만 한 가지 주의할 점이 있어요. useEffect에서는 using 키워드를 쓰는 게 아니라, [Symbol.dispose]를 가진 객체를 return하는 방식입니다. React가 cleanup 시점에 직접 호출해주는 구조라서요.

마무리

이번 RFC를 보면서 React가 'React만의 방식'만 고집하기보다, JavaScript라는 언어의 표준을 적극적으로 받아들이고 있다는 느낌이 들었어요.

JS 생태계의 표준 규격들을 자연스럽게 활용할 수 있게 된다면, 라이브러리 의존도는 낮아지고 코드는 훨씬 더 견고해지겠죠.

이 RFC가 어떤 결론을 맺을지 흥미롭게 지켜보려 합니다. 😆