본문 바로가기

Joyful 디버깅

[React] Can't perform a React state update on an unmounted component. 에러 해결

728x90
반응형

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

 

 

위 에러는 컴포넌트가 언마운트 되어 사용할 수 없는데도 해당 컴포넌트의 state를 바꾸려고 했을 때 나타나는 에러다.

 

에러 메시지를 잘 읽어보면, 아무 실행도 되진 않겠지만, 어플리케이션의 메모리 누수가 발생할 수 있으니 useEffect의 cleanup 함수에 구독과 비동기 작업을 모두 취소하는 방식으로 고칠 수 있다고 한다.

 

 


 

 

내 에러는 아래 코드 때문에 발생했다.

const ProductInfo = () => {

  const [isMobileMode, setIsMobileMode] = useState(window.innerWidth > 991.98 ? false : true);

  window.onresize = throttle(() => {
    window.innerWidth > device.large ? setIsMobileMode(false) : setIsMobileMode(true);
  }, 300);
  
  return (
  	<Wrap>...
  );
  };

 

 

ProductInfo 컴포넌트에는 리사이징을 감지해 화면 너비 값에 따라 isMobileMode state를 변경해주는 함수가 있는데, ProductInfo 컴포넌트가 없는 페이지에서 화면을 리사이징 했을 때도 ProductInfo의 상태 값을 변경하려고 하니 문제가 생기는 것이었다.

 

 


해결방법 

 

에러를 해결하기 위해 에러 메시지에서 나온 useEffect의 cleanup 함수를 이용했다.

 

cleanup 함수란 useEffect에서 return 하는 함수로, 컴포넌트가 언마운트 될 때(사라질 때) 컴포넌트의 뒷정리를 위해 실행되는 함수이다. 

 

const ProductInfo = () => {

  const [isMobileMode, setIsMobileMode] = useState(window.innerWidth > 991.98 ? false : true);

  const resizeEventHandler = throttle(() => {
    window.innerWidth > device.large ? setIsMobileMode(false) : setIsMobileMode(true);
  }, 300);

  useEffect(() => {
    window.addEventListener("resize", resizeEventHandler);
    return () => {
      window.removeEventListener("resize", resizeEventHandler);
    };
  }, [innerWidth]);
  
  return (
  	<Wrap>...
  );
  };

 

resize 이벤트 핸들러 함수를 따로 만들어두고, useEffect에서 resize 이벤트 리스너에 resize 함수를 등록하고, cleanup 함수에서 이벤트 리스너를 삭제하는 방식으로 로직을 변경해주었다.

 

이렇게 하면 ProductInfo 컴포넌트가 마운트 될 때 resize 이벤트가 등록되고, 언마운트될 때에는 resize 이벤트를 삭제해주어 ProductInfo 컴포넌트가 없을 때에는 resize 이벤트가 실행되지 않아 에러가 나타나지 않는다.

 

 

 

 

 

 

참고

https://dev.to/otamnitram/react-useeffect-cleanup-how-and-when-to-use-it-2hbm

https://react.vlpt.us/basic/16-useEffect.html

728x90
반응형