반응형
React를 이용해 어플리케이션을 개발할 때, useRef
로 DOM에 접근해 이벤트를 설정하거나, DOM을 함수 파라미터로 사용하는 경우가 있습니다.
간단한 예시를 통해 먼저 살펴보겠습니다.
App 컴포넌트가 마운트되면, useEffect에서 <div>
태그에 이벤트를 할당하고, unmount될 때, 이벤트를 제거하도록 설정했습니다.
import { useEffect, useRef } from "react";
export default function App() {
const divRef = useRef<HTMLDivElement>(null);
const handleEvent = () => {
alert("click");
};
useEffect(() => {
if (!divRef.current) {
return;
}
divRef.current.addEventListener("click", handleEvent);
return () => {
if (!divRef.current) {
return;
}
divRef.current.removeEventListener("click", handleEvent);
};
}, []);
return <div ref={divRef}></div>;
}
React 16까지는 useEffect의 componentDidMount
부분은 업데이트가 화면에 반영된 직후, 비동기적으로 실행되지만, cleanup 함수(componentWillUnmount
)는 동기적으로 동작하기 때문에, 위와 같이 cleanup 함수를 작성해도 잘 동작합니다.
그러나 React 17부터는 useEffect의 cleanup 함수는 항상 비동기적으로 실행됩니다. 예를 들면, 컴포넌트가 언마운트되면, 화면이 업데이트된 후에 cleanup 함수가 실행됩니다.
따라서, 위 예시의 cleanup 함수가 실행될 때의 divRef.current
는 null
이기 때문에 removeEventListener
가 실행되지 않습니다.
ESLint를 사용하고 있다면 아래와 같은 경고 문구를 확인했을 수 있습니다.
그리고, Chrome 개발자도구에서도 동일한 경고 문구를 확인할 수 있습니다.
해결 방법
이 문제를 해결하기 위해서는 다음과 같은 방법으로 useEffect 함수를 작성하면 됩니다.
import { useEffect, useRef } from "react";
export default function App() {
const divRef = useRef<HTMLDivElement>(null);
const handleEvent = () => {
alert("click");
};
useEffect(() => {
if (!divRef.current) {
return;
}
const divInstance = divRef.current;
divInstance.addEventListener("click", handleEvent);
return () => {
divInstance.removeEventListener("click", handleEvent);
};
}, []);
return <div ref={divRef}></div>;
}
컴포넌트가 언마운트될 때 cleanup 함수가 정상적으로 동작합니다.
참고
반응형
'IT > react' 카테고리의 다른 글
react-router-dom v5, v6 비교 (1) | 2021.12.04 |
---|---|
[React]내가 개발한 사이트의 보안점수 확인하는 방법 (0) | 2021.06.22 |
업로드한 이미지 압축하기(React/browser-image-compression) (0) | 2021.05.27 |
React 어플리케이션 Dockerfile 작성(개발용) (0) | 2020.03.04 |
[React] create-react-app 시, yarn의 unexpected error occurred 해결 (0) | 2020.03.03 |
댓글