문제 상황
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>
);
}
'react' 카테고리의 다른 글
[react] 함수형 컴포넌트 내에 다른 함수형 컴포넌트를 선언할 때 생길 수 있는 문제(trouble-shooting) (0) | 2024.08.01 |
---|---|
[react] setState로 동일한 값을 업데이트하는 문제에 대한 오해 (1) | 2024.04.28 |
[React] 상태관리 라이브러리 비교하기(redux, zustand, jotai, recoil) (0) | 2024.03.22 |
[react] 상태관리 라이브러리는 정말로 필요한가?(context api) (0) | 2024.03.20 |
[react] FLUX 디자인 패턴의 이해2 : 내 방식대로 설명하기 (0) | 2024.03.17 |