알림창 두 번 뜨는 문제 해결하기: useEffect와 StrictMode의 동작 이해하기

verdantgreeny·2025년 2월 24일

본캠프

목록 보기
42/56

문제 발생

개인프로젝트를 진행하던 도중에 로그인을 하지 않은 유저가 MBTI 테스트 버튼을 클릭하면, ProtectedRoutes에 의해 로그인 페이지로 이동하게 된다. 그런데 이때 알림창이 두 번 뜨는 오류가 발생했다.

원인 추론

  const { isAuthenticated } = useContext(AuthContext);
  const { HOME, LOGIN } = ROUTES;
  const navigate = useNavigate();

  useEffect(() => {
    if (!isLogin && !isAuthenticated) {
      // 로그인해야 하는 페이지인데 로그인X
      toast.info("로그인을 해야 테스트가 가능합니다.");
      console.log("useEffect 실행 if 조건");
      navigate(LOGIN);
    } else if (isLogin && isAuthenticated) {
      // 로그인하지 않아야 하는 페이지인데 로그인O
      // toast.info("로그인 상태이므로 홈으로 이동합니다.");
      console.log("useEffect 실행 if else 조건");
      navigate(HOME);
    }
  }, [navigate, isLogin, isAuthenticated]);

  return element;
};

위의 코드가 문제가 발생한 코드이다. 나는 명확한 확인을 위해 콘솔을 찍어 보았는데, useEffect가 2번이나 실행된다는 것을 알 수 있었다.

그런데 특이한 것은 2번째에 찍히는 콘솔은 흐릿한 색깔이라는 점이었다.

문제를 분석해본 결과, useEffect가 두 번 실행되는 이유는 StrictMode가 활성화되어 있기 때문이었다. React의 StrictMode는 함수가 예상대로 동작하는지 확인하려고 일부 컴포넌트에서 코드를 두 번 실행한다. 이로 인해 두 번째 콘솔 로그는 흐릿한 색깔로 출력되었으며, 이는 StrictMode에서 함수가 제대로 동작하는지 검증하려는 과정이었다. 즉, 첫 번째 실행은 정상적인 동작이지만 두 번째 실행은 StrictMode가 동작하는 방식이었다.

해결 방법

이 문제를 해결하기 위해 useRef를 사용하여 알림이 한 번만 뜨도록 만들었다. useRef는 컴포넌트가 리렌더링되더라도 값을 유지할 수 있도록 도와준다. hasAlerted라는 변수를 만들어서 알림이 한 번만 뜨도록 제어했다.

수정한 코드는 다음과 같다.

const ProtectedRoutes = ({ element, isLogin }) => {
  const { isAuthenticated } = useContext(AuthContext);
  const { HOME, LOGIN } = ROUTES;
  const navigate = useNavigate();
  // useEffect가 두번 실행 되는 이유 : stricmode에서 제대로 된 함수인 지 확인하려고 두번 실행해서 검증
  const hasAlerted = useRef(false);

  useEffect(() => {
    if (!isLogin && !isAuthenticated && !hasAlerted.current) {
      // 로그인해야 하는 페이지인데 로그인X
      toast.info("로그인을 해야 테스트가 가능합니다.");![](https://velog.velcdn.com/images/verdantgreeny/post/a0276548-0f41-4565-b620-2a926e044058/image.gif)

      hasAlerted.current = true;
      navigate(LOGIN);
    } else if (isLogin && isAuthenticated && !hasAlerted.current) {
      // 로그인하지 않아야 하는 페이지인데 로그인O
      hasAlerted.current = true;
      navigate(HOME);
    }
  }, [navigate, isLogin, isAuthenticated]);

  return element;
};

위 코드에서 useRef를 사용하여 hasAlerted.current 값이 true로 설정되면 이후에는 알림을 띄우지 않도록 했다. 이렇게 수정함으로써 알림창이 두 번 뜨는 문제를 해결했다.

결과

수정한 후 더 이상 알림창이 두 번 뜨지 않음을 확인할 수 있었다. 이제 로그인하지 않은 상태에서 MBTI 테스트 버튼을 클릭하면, 로그인 페이지로 이동하면서 알림이 한 번만 표시된다.

++ 나중에는 그냥 알람을 삭제하였다.

  • 최종 코드
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { ROUTES } from "../constants/routes";
import useAuthStore from "../zustand/bearsStore";

const ProtectedRoutes = ({ element, isLogin }) => {
  const { isAuthenticated } = useAuthStore();
  const { HOME, LOGIN } = ROUTES;
  const navigate = useNavigate();

  useEffect(() => {
    if (!isLogin && !isAuthenticated) {
      // 로그인해야 하는 페이지인데 로그인X
      navigate(LOGIN);
    } else if (isLogin && isAuthenticated) {
      // 로그인하지 않아야 하는 페이지인데 로그인O
      navigate(HOME);
    }
  }, [isLogin, isAuthenticated]);

  return element;
};

export default ProtectedRoutes;

0개의 댓글