useNavigationLock
페이지 이탈 시 사용자에게 경고를 표시하는 커스텀 훅Next.jsReactTypescript
예시
페이지 이탈이 허용됩니다.
API
useNavigationLock()- Parameters
- shouldBlock (boolean)이탈 경고를 활성화할지 여부 (기본값: true)
- Returns
- void (void)이 훅은 값을 반환하지 않습니다.
개발 및 사용환경
Next.jsReactTypescript사용법
1// 폼이 수정되었을 때 이탈 방지
2const [isFormDirty, setIsFormDirty] = useState(false);
3useNavigationLock(isFormDirty);
4
5// 특정 조건에서만 이탈 방지
6useNavigationLock(hasUnsavedChanges);
7
8// 이탈 방지 비활성화
9useNavigationLock(false);
Hook
1import { useRouter, usePathname } from "next/navigation";
2import { useEffect, useCallback } from "react";
3
4/**
5 * 페이지 이탈 시 사용자에게 경고를 표시하는 Hook
6 *
7 * @remarks
8 * - Chrome, Firefox, Safari, Edge 등 모던 브라우저에서 지원됩니다.
9 * - 모바일 브라우저에서는 동작이 제한적일 수 있습니다.
10 * - beforeunload 이벤트를 사용하므로, 실제 메시지 내용은 브라우저마다 다르게 표시될 수 있습니다.
11 *
12 * @param shouldBlock - 이탈 경고를 활성화할지 여부 (기본값: true)
13 */
14export function useNavigationLock(shouldBlock: boolean = true) {
15 const router = useRouter();
16 const pathname = usePathname();
17
18 const handleBeforeUnload = useCallback(
19 (event: BeforeUnloadEvent) => {
20 if (shouldBlock) {
21 event.preventDefault();
22 event.returnValue = "";
23 }
24 },
25 [shouldBlock]
26 );
27
28 useEffect(() => {
29 if (!shouldBlock) return;
30
31 // 브라우저 새로고침/닫기 방지
32 window.addEventListener("beforeunload", handleBeforeUnload);
33
34 // 뒤로가기/앞으로가기 방지
35 const handlePopState = (e: PopStateEvent) => {
36 if (shouldBlock) {
37 e.preventDefault();
38 window.history.pushState(null, "", window.location.href);
39 if (
40 window.confirm(
41 "저장되지 않은 변경사항이 있습니다. 정말로 나가시겠습니까?"
42 )
43 ) {
44 window.history.back();
45 }
46 }
47 };
48
49 // 클라이언트 사이드 네비게이션 방지
50 const handleClick = (e: MouseEvent) => {
51 const target = e.target as HTMLElement;
52 const anchor = target.closest("a");
53
54 if (
55 anchor &&
56 anchor.href &&
57 !anchor.href.startsWith("javascript:") &&
58 anchor.href !== window.location.href
59 ) {
60 e.preventDefault();
61 if (
62 window.confirm(
63 "저장되지 않은 변경사항이 있습니다. 정말로 나가시겠습니까?"
64 )
65 ) {
66 router.push(anchor.href);
67 }
68 }
69 };
70
71 window.addEventListener("popstate", handlePopState);
72 document.addEventListener("click", handleClick);
73
74 // 초기 히스토리 상태 추가
75 window.history.pushState(null, "", window.location.href);
76
77 return () => {
78 window.removeEventListener("beforeunload", handleBeforeUnload);
79 window.removeEventListener("popstate", handlePopState);
80 document.removeEventListener("click", handleClick);
81 };
82 }, [shouldBlock, router, handleBeforeUnload]);
83}