본문 바로가기

react

[react] useEffect에서 clean up함수를 사용하면서 early return하기

문제 상황


useEffect는 react에서 side effect를 처리하기 위해 많이 사용된다.

clean up은 useEffect의 첫 번째 인자인 함수에서 return되는 함수이다.

클린 업 함수는 컴포넌트가 디스마운트되는 시점에 실행되므로 리소스를 해제할 때 사용한다.

가령, 컴포넌트에 한 addEventListener이 있다면 클린 업 함수에서 removeEventListener로 해제한다.

 

문제는 useEffect 내에서 early return을 하고 싶을 때다.

early return으로 복잡한 조건문을 해결하고 싶을 때 clean up 함수를 어떻게 처리할까.

결과 요약
useEffect 내부나 외부에서 clean up을 위한 함수를 미리 만들어 놓고 모든 early return 때 반환해주면 된다.

 

실험 설계


이 부분에 대한 마땅한 레퍼런스를 찾지 못해서 직접 실험해봤다.

구상은 이러하다.

 

  • app 컴포넌트에 test 컴포넌트를 만든다.
  • test컴포넌트에 useEffect로 이벤트를 바인딩한다. 그리고 클린 업 함수로 이벤트를 해제해줄 수 있게 한다.
  • 위 useEffect에 early return문을 넣는다.
  • early return문을 실행할 수 있으면서, 디스마운트 시 클린업 함수도 작동할 수 있는 방법 X를 찾아본다,

 

실험 시작


예시 코드를 보자.

//@ app.jsx
import { useState } from "react";
import Test from "./component/Test";

function App() {
  const [isShowTest, setIsShowTest] = useState(true);
  return (
    <div className="App">
      <button onClick={() => setIsShowTest((prev) => !prev)}>
        mount toggle
      </button>
      {isShowTest ? <Test /> : ""}
    </div>
  );
}

export default App;
//@Test.jsx
import { useEffect, useRef } from "react";

export default function Test() {
  const handleClick = () => console.log("click");
  function validation() {
    return false;
  }

  useEffect(() => {
    document.addEventListener("click", handleClick);
    if (!validation()) return;
    return () => {
      console.log("클린 업 실행 중");
      document.removeEventListener("click", handleClick);
    };
  }, []);

  return (
    <div>
      <p>test box</p>
    </div>
  );
}

 

코드 설명

test 컴포넌트

- useEffect에서 document에 "click"을 콘솔 출력하는 handleClick 이벤트를 할당한다.

- clean up 함수로 이벤트 리스너를 정리한다.

- validation 함수로 useEffect의 코드를 early return한다.

document에 이벤트 리스너를 부착한 이유는, 만약 test 컴포넌트에 이벤트 리스너를 부착할 시 컴포넌트가 언마운트 될 때 자동으로 이벤트 리스너가 정리된다. 따라서 클린업 내 이벤트 리스너 부착 해제를 제대로 확인할 수 없다.

실제로 클린업은 React 컴포넌트의 생명주기 관리 외부에 있는 이벤트리스너를 해제할 때 사용되므로
test 컴포넌트의 생명주기 외부에 있는 document에 이벤트 리스너를 부착했다.

 

app 컴포넌트

- 버튼으로 test 컴포넌트를 마운트하거나 디스마운트 한다.

 

결과

디스마운트 시 클린 업 함수로 이벤트 리스너를 정리해야 하지만, validation 함수를 이용한 early return으로 실패했다.

일반적으로 클린 업 함수는 useEffect 문의 가장 아래에 위치하기 때문에 이런 방식으로 early return을 설정하면 실패한다는 걸 알았다.

 

 

해결 방법


해결방법은 간단하다.

useEffect 내부나 외부에서 clean up함수를 정의하고 early return에서 반환 값으로 설정해주면 된다. 

import { useEffect, useRef } from "react";

export default function Test() {
  const handleClick = () => console.log("click");
  function validation1() {
    return false;
  }

  function validation2() {
    return false;
  }

  function validation3() {
    return false;
  }

  useEffect(() => {
    const cleanUp = () => {
      console.log("클린 업 실행 중");
      document.removeEventListener("click", handleClick);
    };
    document.addEventListener("click", handleClick);
    if (!validation1()) return cleanUp;
    if (!validation2()) return cleanUp;
    if (!validation3()) return cleanUp;
  }, []);

  return (
    <div>
      <p>test box</p>
    </div>
  );
}