개발/프로젝트

새로고침/뒤로가기 시도 시 모달 띄우기

xuwon 2025. 5. 27. 15:44

일기 작성 페이지에서 새로고침, 뒤로가기 등을 시도할 때 이동을 막고 경고 모달을 띄우려고 한다.

 
 

const router = useRouter();
const pathname = usePathname(); // 현재 경로
const lastPathname = useRef(pathname); // 이전 경로 저장
useEffect(() => {
  if (pathname !== lastPathname.current) {
    // 페이지 이동 시도 감지
    setShowSaveRestrictionModal(true); // 모달 띄우기

    router.replace(lastPathname.current); // 현재 페이지로 강제 이동 → 이동 막기
  }
}, [pathname, router]);

pathname이 바뀌면, 즉 사용자가 라우터 이동을 시도하면 감지됨
그리고 router.replace(lastPathname.current)를 통해 현재 페이지로 강제 이동을 시킨다.

→ 페이지 변경 X

 

useEffect(() => {
  const handleBeforeUnload = (e: BeforeUnloadEvent) => {
    e.preventDefault();         // 크롬 기준으로 꼭 넣어야 동작
    e.returnValue = '';         // 브라우저 기본 경고창 띄움
  };

  window.addEventListener('beforeunload', handleBeforeUnload);

사용자가 브라우저에서 새로고침이나 탭을 닫을 때, 브라우저 기본 경고창을 띄운다.
(beforeunload 이벤트)
이건 커스텀 모달은 못 넣는다고 한다.

  window.history.pushState(null, '', window.location.href);

히스토리(브라우저의 방문 내역 스택)에 현재 상태를 강제로 push하는 코드.

브라우저 자체의 뒤로가기 버튼을 눌렀을 때 페이지가 이동하는 것을 방지하기 위해서 덫을 깔아놓는 셈이다.

  const handlePopState = () => {
    setShowSaveRestrictionModal(true);             // 모달 띄우기
    window.history.pushState(null, '', window.location.href); // 다시 현재 주소 push
  };

  window.addEventListener('popstate', handlePopState);

여기서 popstate 이벤트는 뒤로가기(or 앞으로가기) 할 때 발생된다.
이때 내가 만든 모달을 띄우고, 또 현재 주소를 push 해서 히스토리를 원래대로 되돌린다.

→ 뒤로가기 클릭 무력화

  return () => {
    // 클린업
    window.removeEventListener('beforeunload', handleBeforeUnload);
    window.removeEventListener('popstate', handlePopState);
  };
}, []);

컴포넌트 언마운트 시 이벤트 리스너 정리!
어렵다.