본문 바로가기
IT/react

useEffect의 cleanup 함수 내에서 DOM Ref 사용하기

by Josh.P 2021. 5. 28.
반응형

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.currentnull이기 때문에 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 함수가 정상적으로 동작합니다.

참고

 

React v17.0 Release Candidate: No New Features – React Blog

Today, we are publishing the first Release Candidate for React 17. It has been two and a half years since the previous major release of React, which is a long time even by our standards! In this blog post, we will describe the role of this major release, w

ko.reactjs.org

 

반응형

댓글