회원가입, 글쓰기 등 입력 Form 페이지에서 실수로 다른 링크를 클릭하거나, 저장하는 것을 깜빡하고 다른 페이지로 이동하면 유저 입장에서 무척 짜증나는 상황이 된다. 처음부터 폼을 다시 작성하거나 수정해야 하기 때문이다. 임시 저장 기능이 있다면 괜찮지만, 그렇지 않다면 페이지 이탈에 대한 Confirm 단계를 추가해서 사용성을 개선할 수 있다. 실제로 여러 웹 서비스에서 Form 페이지 이탈시 ‘저장하지 않은 내용은 삭제된다’는 안내 문구를 띄운다.
NextJS 자체적으로 여러 라우트 이벤트를 제공하는데 routeChangeStart는 라우트 변경을 시작할 때 트리거되는 이벤트다. 페이지를 언로드(새로고침)할 땐 window
객체에서 발생하는 beforeunload 이벤트를 이용하면 된다. 대략 아래 4가지 단계를 통해 구현한다.
<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> router.replace는 history stack에 있는 가장 마지막 요소를 이동할 경로로 대체한다. 즉 현재 페이지를 새로운 페이지로 덮어쓴다. 그 외엔 router.push와 동일하다. — 참고 노트
push
이용시
'/'
→ '/profiles'
→ '/profiles/smith'
'profiles'
['/', 'profiles', 'profiles/smith']
replace
이용시
'/'
(push) → '/profiles'
(replace) → '/profiles/smith'
'/'
['/', 'profiles/smith']
</aside>true
: 다른 페이지로 이동(페이지 이탈)false
: 페이지 이동 취소1-b
에서 임시 저장한 경로로 복구 — *router.replace(...)*
임시 저장한 경로로 router.replace
를 실행하면(4-a
) 라우트 변경을 시도하므로 routeChangeStart 이벤트가 발생한다. 그럼 이벤트 핸들러가 실행돼서 위 과정을 또 다시 반복하며 무한 렌더링된다. 이를 방지하려면 라우트 변경을 취소했을 때만 이벤트 핸들러를 실행하도록 해야 한다. 이를 위해 isKilledRouter
같은 내부 상태로 라우트 변경 취소 여부를 관리한다.
isKilledRouter 값 (라우트 변경 취소 여부) | routeChangeStart 핸들러 실행 여부 |
---|---|
true | ❌ |
false | ✅ |
유저가 페이지 이동을 취소한 후 다시 페이지 이동을 시도하는 상황도 고려해야 한다. 즉, 1~4번 단계까지 한 사이클 실행을 마친 뒤에도 다음 사이클에서 이벤트 핸들러가 실행될 수 있도록 isKilledRouter
상태를 false
로 바꿔주는 작업이 필요하다.
<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> 참고 내용
then
후속 메서드의 콜백은 마이크로태스크큐에 들어갔다가 콜스택이 비었을 때 실행된다get...Props
)가 실행된다. 데이터 패칭 메서드를 실행하지 않고 URL을 변경하고 싶을 땐 shallow: true
옵션을 넘긴다. — 참고글router.*
메서드를 실행하면 내부 상태 값을 변경하므로 리렌더링이 발생한다. window.history.replaceState
를 사용하면 리액트와 상관없는 히스토리 객체를 핸들링하기 때문에 리렌더링이 발생하지 않는다. — 참고글
</aside>커스텀훅이 받는 shouldStopNavigation
파라미터가 true
라면 routeChangeStart 이벤트 핸들러가 등록된다. 그 후 유저가 페이지 이동(라우트 변경)을 시도하면 onRouteChange
이벤트 핸들러를 실행한다.