ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클린업 함수를 사용한 오류해결 - (Can't perform a React state update on an unmounted component)
    오류 2022. 1. 9. 13:09

    개인 프로젝트 작업을 하던중 어김없이 오류를 발견했다. 

    해석해보자면 언마운트된 컴포넌트에선 리액트상태 업데이트를 할수가 없다.

    이작업은 수행되지는 않지만 메모리 누수가 발생한다.

    클린업 함수를 써서 고쳐봐라.

     

    대강 이런내용이다. 이전에 작성한 글에서 본 오류내용과 흡사하고 로직과 기능또한 비슷하지만

    발생 시점자체가 다르다.

     

    발생한 코드

    const JoinMain = () => {
      const [JoinFailAlert, setJoinFailAlert] = useState(false);
    
      useEffect(() => {
        setTimeout(() => {
          setJoinFailAlert(false);
        }, 5000);
      }, [JoinFailAlert]);
      
    
      return (
        <>
          {JoinFailAlert && (
            <Alert severity="error">
              <AlertTitle>회원가입 실패</AlertTitle>
              <strong>작성 안한 칸이 있거나 확인비밀번호가 맞지 않습니다.</strong>
            </Alert>
          )}
        </>
      );
    };
    
    export default JoinMain;

     

     

     

    이전글에서의 오류

    자세한 내용은 이전글을 확인해주길 바란다.

     

    위에 오류같은경우는 상위컴포넌트에서 하위컴포넌트를 꺼주고 켜주는 시점에서 발생한 문제이다.

    버튼에 클릭이벤트가 발생하면 컴포넌트를 활성화후 로직을 수행하고 본인 컴포넌트를 꺼주는식으로 작동한다(setState 사용)

    클린업함수는 쓰지도 않았고 단순하게 useEffect에 defs를 넣지않고 해결해주었다.

     

    하지만 이번오류의 내용은 조금다른데

    해당 컴포넌트에선 문제없이 작동했지만 page를 이동하는 시점에서

    발생한 오류이다. (정확히는 페이지를 이동하고 조금 지난후)

     

    이전글을보면 하위컴포넌트에서 로직을 수행하긴 하지만 관리하고 있는 상태변수가 상위 컴포넌트에 있기때문에

    비동기 작업을 수행하더라도 바꿔줄 상태값이 있기때문에(불필요한 메모리사용이 아니기때문에) 오늘 다룰 오류가 발생하지 않았다.

     

    이번오류같은경우 비동기 작업 수행을 대기하던 도중 바꿔주어야 할 상태가 언마운트되버린 상황에서 시도하고 있기때문에 불필요한 메모리를 사용하고 있다.

     

    언마운트되면 해당컴포넌트의 state는 초기화되고 더이상 로직을 수행하지 않는데 왜 그러지? 하고 생각할수 있다.

    이부분은 javascript의 이벤트루프를 이해하고 있다면 왜이런 오류가 발생했는지 어떻게 해결해야할지 감이 올것이다.

    이벤트루프를 설명하는건 이번글에서 작성하긴 분량이 많고 나보다 훨씬 잘 정리한 글이 있으므로 해당글을 참고로 해주면 감사하겠다.

     

     

    오류를 이해하기 위한 부분을 정리하자면

    js는 단일스레드 즉 한번에 하나의 작업만 수행하고 해당 작업이 끝날때까진 어떤 함수의 방해도 받지 않는다.

    하지만 실제 우리가 쓰는 js는 동시성이 없다고 말할순 없을것이다.

    '자바스크립트 엔진이 단일 호출 스택을 사용한다'는 관점에서만 사실이다

    여기서 말하는 js의 단일스레드는 단일호출스택을 말하는것인데 비동기함수는 스택에요청후 바로 삭제되고

    webAPI의 태스크큐에 저장되어 스택이비워질때마다 콜백함수를 스택에추가해 독립적인 컨텍스트에서 실행된다.

     

    오류와 연관지어 좀더 간단하게 설명한다면

    마운트후 호출스택에 있는 코드들이 실행되고 page를 이동해 언마운트가 됬는데 태스크큐에서 실행을 기다리고 있는 setTimeout엔 state를 변경하는 함수가 있기때문에 쓸데없는 메모리 누수가 발생한다.

     

    왜 발생하는지는 알게됬으니 고칠일만 남았다.

     

    언마운트된후에 환경변수를 바꾸는게 메모리 누수가 된다면 미리 언마운트되는 시점에 환경변수를 바꿔주면 되겠다.

    이제 경고창에서 제시한 클린업함수를써보자 useEffect훅에선 언마운트는 빈defs와 return으로 구현할수 있다.

     

    const JoinMain = () => {
      const [JoinFailAlert, setJoinFailAlert] = useState(false);
    
      useEffect(() => {
        setTimeout(() => {
          setJoinFailAlert(false);
        }, 5000);
      }, [JoinFailAlert]);
    
      useEffect(() => {
        return () => {
          setJoinFailAlert(false)
        };
      }, []);//클린업함수
      
    
      return (
        <>
          {JoinFailAlert && (
            <Alert severity="error">
              <AlertTitle>회원가입 실패</AlertTitle>
              <strong>작성 안한 칸이 있거나 확인비밀번호가 맞지 않습니다.</strong>
            </Alert>
          )}
        </>
      );
    };
    
    export default JoinMain;

    다른 page로 가기전에 꺼주는 함수 클린업 함수이다.

    이함수는 공식처럼 사용하기도 한다.

     

     

     

     

     

     

     

Designed by Tistory.