
지난 기간 동안 수많은 프로젝트를 거쳐오면서 게시글을 작성하고 있을 때 사용자가 실수로 뒤로가기를 누르거나 브라우저를 닫아버린 경우 '작성하던 내용이 모두 사라질텐데 정말로 계속하겠느냐'는 알림 처리를 해보면 좋을 것 같다는 피드백을 많이 받았었다.
이번 최종 플젝으로 input, checkbox, radio, file, textarea 등 정말 다양한 종류의 input 태그를 다루는 에디터 페이지를 개발하면서 페이지 이탈 방지 처리를 꼭 해봐야겠다는 생각을 했다.
Next.js를 배우면서 페이지 간 이동을 할 때 push, replace 등useRouter를 곧잘 사용했었는데, next/navigation에서 import 해와야 사용할 수 있다. 한번씩 실수로 next/router에서 잘못 가져오면 에러가 발생했었는데, 그럼 대체 사용하지도 않는 next/router는 왜 import 하려고 할 때마다 자동완성에 같이 뜨는걸까 궁금했었다.
예전에는 useRouter 훅을 next/router모듈에서 import 해와서 썼다고 하는데 Next.js 13버전? 14버전부터 next/navigation에서 import 해오는 걸로 바뀌었다는 것 같다. 이렇게 변경되면서 기존 next/router에서 사용할 수 있었던 함수 중 일부만 사용할 수 있도록 변경되었다고 한다.
chatGPT 선생님께 페이지 이탈 방지에 대해서 질문하니 계속 예전 버전으로 구현하는 방식을 이야기하길래 쉽게 답을 찾기가 어려웠다😢😢😢
처음에 이 방법대로 코드를 작성해봤더니 NextRouter was not mounted. 에러가 발생했다.
바뀐 next/navigation에서의 useRouter에는 events가 없어서 기존 방식대로는 구현할 수 없었던 것이다.
우선 커스텀 훅으로 만든 다음 컴포넌트에서 import 해서 사용하고 싶어서 useConfirmPageLeave.tsx를 새로 만들어줬다.
페이지가 마운트 될 때 이벤트 리스너를 등록하고, 언마은트될 때 이벤트 리스너를 제거하는 방식으로 구현하기 위해 useEffect를 사용하여 코드를 작성해주었다.
BeforeUnloadEvent는 사용자가 페이지를 떠나거나 새로고침 하려고 할 때 발생하는 이벤트로, 일반적으로 페이지를 닫기 전에 사용자에게 경고를 표시하거나 변경사항을 저장하라는 메시지를 표시할 때 사용되는 이벤트 객체이다.
e.preventDefault()를 통해 이벤트의 기본 동작(여기서는 페이지의 언로드)을 중단시키고, returnValue를 사용해서 사용자에게 표시되는 메시지를 문자열로 설정할 수 있다. 과거에는 이 속성을 대부분의 브라우저에서 지원했지만, 최신 웹 표준에 따르면 이것은 오래된 방식으로 권장되지 않는 코드라고 한다. 그러나 몇 브라우저에서는 여전히 이 부분이 없으면 호환성 문제가 있을 수 있으니 적어주는 게 좋다고 한다.
import { useEffect } from 'react';
const useConfirmPageLeave = () => {
useEffect(() => {
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
event.preventDefault();
event.returnValue = '';
return '작성하던 내용이 모두 사라집니다. 계속하시겠습니까?';
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []);
};
export default useConfirmPageLeave;
일부 브라우저는 코드에 작성한 문자열을 무시하고 기본 메시지를 표시할 수 있다고 한다. (크롬이 바로 그 일부 브라우저 인가보다. 내가 작성한 문자열이 보이지 않는다.)
내일은 input에 입력값이 있는 경우에만 뒤로가기 및 페이지 이동 시도할 때에도 이탈 방지 처리를 추가해봐야겠다.