Next router 이동 시 알림창 띄울 때 window.onbeforeunload 작동 안되는 문제 해결법

next.js 에서 window.onbeforeunload 가 작동하지 않는 문제가 있었다...

새로고침 할 때는 작동하는데 라우터 이동 시에만 작동안하는 문제를 해결하려고 구글을 뒤져서 찾아냈다

 

https://stackoverflow.com/questions/63064778/next-js-warn-user-for-unsaved-form-before-route-change

 

Next JS: Warn User for Unsaved Form before Route Change

In Next How can i stop Router Navigation in Next JS. I am trying to use routerChangeStart event to stop navigation. useEffect(() => { const handleRouteChange = (url: string): boolean => {...

stackoverflow.com

 

// 리로드할 시점(form 수정중이라던라 등등... 없어도 무관)
const [reload, setReload] = useState(false);

useEffect(() => {
  const confirmMsg = `사이트에서 나가시겠습니까?\n변경사항이 저장되지 않을 수 있습니다.`;
  
  // 리로드 전에 메세지 띄워주기
  const handleBeforeUnload = (e: BeforeUnloadEvent) => {
    (e || window.event).returnValue = confirmMsg;
    return confirmMsg; // Gecko + Webkit, Safari, Chrome
  };
  
  //라우터 바뀌기 전 이벤트(취소했을경우 넘어가지않음)
  const handleBeforeChangeRoute = (url: string) => {
    if (router.pathname !== url && !confirm(confirmMsg)) {
      router.events.emit("routeChangeError");
      throw `사이트 변경 취소`;
    }
  };

  if (reload) {
    window.addEventListener("beforeunload", handleBeforeUnload);
    router.events.on("routeChangeStart", handleBeforeChangeRoute);
  } else {
    window.removeEventListener("beforeunload", handleBeforeUnload);
    router.events.off("routeChangeStart", handleBeforeChangeRoute);
  }

  return () => {
    window.removeEventListener("beforeunload", handleBeoreUnload);
    router.events.off("routeChangeStart", handleBeforeChangeRoute);
  };
}, []);

 

이제 라우터 이동 시에 알림창이 뜨면서 페이지 이동하시겠습니까?(예/아니오) 선택에 따라 제한할 수 있다

 

하지만 여기에서 문제는 또 발생하는데... (ㅠㅠㅠㅠㅠㅠ)

라우터이동은 막혔지만 뒤로가기 버튼을 눌렀을 때 url은 변경되어버린다

* 예) 메인에서 글작성으로 이동 > 글작성 중 뒤로가기 > url만 메인으로 돌아가고 화면은 글작성중

 

크롬에서 유저가 사이트 내에서 못빠져나가는 것을 방지하기 위해 막아뒀다고 들었는데(팩트체크x 체크되면 수정하겠습니다)

 

뒤로가기 시 url 이 변경되지 않게 하기 위해서는 (if reload 안에) 아래 코드를 추가해야한다

// 중요! 페이지 뒤로가기 시 url 은 변경되는 문제가 있는데 그걸 해결해줌
if (router.asPath !== window.location.pathname) {
  window.history.pushState("", "", router.asPath);
}

 

+ 추가로 새로고침시에만 알림창 나오게 하기

useEffect(() => {
  // 새로고침 막기(조건 부여 가능)
  window.onbeforeunload = function () {
    return true;
  };
  return () => {
    window.onbeforeunload = null;
  };
}, [])
반응형