navigate(-1)의 위험성: 브라우저 히스토리에서 이전 위치로 이동, 앱 내부 네비게이션과 혼란을 초래할 수 있음- 대신
Link컴포넌트의state속성을 활용하여 안전하게 앱 내에서의 “Back” 네비게이션 구현 가능 - 사용자에게 현재 URL을 반환하는 커스텀 훅
useCurrentURL구현 및 재사용의 용이성을 제공하는useBackNavigation훅 정의
function PreserveStateLink(props) {
const location = useLocation()
const currentURL = location.pathname + location.search
return (
<Link state={{ back: currentURL }} {...props}>
{children}
</Link>
)
}
function BackLink() {
const navigate = useNavigate()
const location = useLocation()
const handleClick: LinkProps['onClick'] = (e) => {
const back = location.state?.back
if (back) {
e.preventDefault()
navigate(back)
}
}
return (
<Link to="/todos" onClick={handleBack}>
Back
</Link>
)
}Navigation API에서 traverse(뒤/앞 이동)만 preventDefault()로 막을 수 없다. push·replace·reload는 취소 가능, traverse는 취소 정의역 밖.
그래서 traverse blocker는 사전 차단이 아니라 사후 롤백이다 — 이동은 이미 일어났으니 되돌린다:
// traverse가 이미 go(n)을 일으킴 → blocker는 go(-n)으로 원위치
onNavigate(e) {
if (blocked) history.go(-delta) // 관측상 항등 ("리스트 + 커서" 모델이라)
}
정의역 조건(0 ≤ idx + n) 안에서만 항등. 형식 닻: go_rollback_id — go n 다음 go (-n) = h.
곁가지 (같은 list+cursor 모델의 다른 비대칭):
- navigationType에서
reload·traverse가 같은 POP으로 뭉개짐(정보 손실) → idx 변화량delta로 구분. - 내부 호출이 쏜 navigate 이벤트는
info태그로 흡수 → 재진입 종료.