next router 라우팅 블로킹

김혜진·5일 전
0

작성한지 약 2년이 지나 nextjs 15가 나온 시점이고 해당 레포는 파일 라우팅으로 전환되어있지만.. 임시저장에 있는 글을 올려본다.. 현재는 많이 달라졌을 수 있는 점 주의

상황

nextjs 라우터를 커스텀하게 사용하고 있고, 뒤로 가기 등 원하는 시점에 라우팅 블로킹을 하고 싶음

원인

browser history를 알 수 없음

시도 한 것

router events

  • routeChangeStart
    - custom router라 그런가 push state가 정상적으로 되지 않음
  • beforeHistoryChange
    - router back을 하는 것이기 때문에 history가 변경되는 게 아니라 트리거 되지 않음

browser before unload event

크로스 브라우징이 안됨 ㅜㅜ

popstate event

ing

pushState로 업데이트를 해주고 routeChangeStart 사용하여 막으나 router이동을 막을 수는 없음. 수동으로 히스토리를 끼워맞춰주니까 히스토리가 꼬임 ㅜㅜ

  • pushState해서 히스토리 변경해주고 replace로 라우트 변경
  • useCallback으로 감쌌으나 reference가 계속 변경되고 있었음
  • 기본 프롬프트가 아닌 커스텀 드로워를 띄워주고 싶음
  • router push가 아니라 back을 사용하니 바로 넘어가버림

최종 코드

import { useRouter } from 'next/router';
import { useCallback, useEffect, useRef, useState } from 'react';

interface UseBlockProps {
  when?: boolean;
  callback: () => Promise<boolean | undefined>;
}

export const useBlock = ({ when, callback }: UseBlockProps) => {
  const router = useRouter();
  const unblockRef = useRef<() => unknown>();
  const callbackRef = useRef<() => Promise<boolean | undefined>>();

  callbackRef.current = callback;

  const unblock = useCallback(() => {
    unblockRef.current?.();
  }, []);

  const handleRouteChangeStart = useCallback(
    async (url: string) => {
      try {
        if (url === router.asPath) {
          return;
        }

        setTimeout(() => {
          router.replace(router.asPath, undefined, { shallow: true });
          window.history.pushState(null, '', router.asPath);
        }, 0);

        if (when) {
          if (await callbackRef.current?.()) {
            unblock();
            router.back();
          }
        }
      } catch (error) {
        console.error(error);
      }
    },
    [router.asPath],
  );

  useEffect(() => {
    router.events.on('routeChangeStart', handleRouteChangeStart);

    unblockRef.current = () => router.events.off('routeChangeStart', handleRouteChangeStart);
  }, [router, handleRouteChangeStart]);

  return { unblock };
};

profile
개발하고 있습니다

0개의 댓글