[Next.js] 안전한 뒤로가기 구현하기: router.back()만으로 부족할 때
포스트
취소

[Next.js] 안전한 뒤로가기 구현하기: router.back()만으로 부족할 때

🧐 들어가며: 뒤로가기는 생각보다 까다로워요

상세 페이지나 결제 페이지를 만들다 보면 이전으로 버튼이 필요할 때가 많습니다.

처음에는 단순하게 router.back()을 사용하면 충분해 보입니다.

1
router.back();

하지만 실제 서비스에서는 몇 가지 애매한 상황이 생깁니다.

  • 검색이나 광고를 통해 상세 페이지로 바로 들어온 사용자는 돌아갈 내부 페이지가 없습니다.
  • 외부 사이트에서 들어온 사용자를 다시 외부 사이트로 내보낼 수 있습니다.
  • 브라우저 히스토리만 보고 판단하면 서비스 내부 이동인지 알기 어렵습니다.

그래서 뒤로가기 버튼을 만들 때는 정말 뒤로 가도 되는 상황인지를 먼저 확인하고, 그렇지 않으면 안전한 경로로 이동시키는 fallback 처리가 필요합니다.


💡 기본 아이디어

안전한 뒤로가기를 만들기 위해 두 가지를 함께 확인했습니다.

  1. 브라우저에 이전 히스토리가 있는지
  2. 이전 페이지가 현재 서비스 내부 페이지인지

이때 사용할 수 있는 값이 window.history.lengthdocument.referrer입니다.

1
2
const hasHistory = window.history.length > 1;
const isInternalNavigation = document.referrer.includes(window.location.host);

hasHistory는 브라우저 세션 히스토리에 이전 기록이 있는지 확인하고, isInternalNavigation은 이전 페이지가 현재 서비스 도메인인지 확인합니다.

둘 다 만족할 때만 router.back()을 실행하고, 그렇지 않으면 미리 정한 경로로 이동시키면 됩니다.


🛠️ 구현 코드

Next.js에서 사용할 수 있는 형태로 정리하면 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { useRouter } from "next/navigation";

export const useSmartBack = (fallbackPath = "/") => {
  const router = useRouter();

  const goBack = () => {
    const hasHistory = window.history.length > 1;
    const isInternalNavigation = document.referrer.includes(
      window.location.host,
    );

    if (hasHistory && isInternalNavigation) {
      router.back();
      return;
    }

    router.push(fallbackPath);
  };

  return { goBack };
};

사용하는 쪽에서는 이렇게 호출할 수 있습니다.

1
2
3
4
5
6
7
const { goBack } = useSmartBack("/characters");

return (
  <button type="button" onClick={goBack}>
    이전으로
  </button>
);

이렇게 하면 내부 목록 페이지에서 상세 페이지로 들어온 사용자는 자연스럽게 이전 페이지로 돌아가고, 외부에서 바로 들어온 사용자는 /characters 같은 안전한 경로로 이동합니다.


📌 window.history.length

window.history.length는 현재 브라우저 탭의 세션 히스토리 개수를 알려줍니다.

1
const hasHistory = window.history.length > 1;

새 탭에서 현재 페이지를 처음 열었다면 보통 1입니다. 그래서 1보다 크면 이전 기록이 있다고 볼 수 있습니다.

다만 이것만으로는 부족합니다. 이전 기록이 있더라도 그 기록이 우리 서비스 내부 페이지인지, 검색 엔진이나 메신저 같은 외부 페이지인지는 알 수 없기 때문입니다.


📌 document.referrer

document.referrer는 현재 페이지로 오기 전 페이지의 URL을 담고 있습니다.

1
const isInternalNavigation = document.referrer.includes(window.location.host);

이 값에 현재 서비스의 host가 포함되어 있다면 내부 페이지에서 이동해온 것으로 판단할 수 있습니다.

다만 document.referrer도 항상 완벽한 값은 아닙니다. 직접 URL을 입력하거나, 브라우저 보안 정책에 따라 referrer가 비어 있을 수 있습니다.

그래서 history.lengthreferrer를 함께 확인하는 편이 더 안전합니다.


📊 방식 비교

방식장점아쉬운 점
router.back()만 사용구현이 가장 간단함외부 페이지로 돌아갈 수 있음
history.length만 확인이전 기록 유무를 알 수 있음내부 이동인지 알 수 없음
referrer까지 확인내부 이동 여부를 함께 판단 가능referrer가 비어 있는 경우를 고려해야 함

완벽한 정답이라기보다는, 사용자를 서비스 밖으로 갑자기 내보내지 않기 위한 안전장치에 가깝습니다.


⚠️ 주의할 점

이 방식은 브라우저 환경에서만 동작합니다. windowdocument를 사용하기 때문에 서버 컴포넌트나 서버 렌더링 중에는 직접 실행하면 안 됩니다.

Next.js App Router에서는 클라이언트 컴포넌트 안에서 버튼 클릭 이벤트로 실행하는 방식이 가장 자연스럽습니다.

document.referrer는 정책에 따라 비어 있을 수 있으므로, referrer가 없을 때 이동할 fallback 경로를 반드시 준비해두는 것이 좋습니다.


✅ 마무리

뒤로가기 버튼은 작아 보이지만, 사용자의 이동 흐름을 크게 좌우합니다.

router.back()만 사용하면 간단하지만, 외부 유입 사용자를 예상하지 못한 곳으로 보내버릴 수 있습니다.

window.history.length로 이전 기록이 있는지 확인하고, document.referrer로 내부 이동인지 한 번 더 확인하면 조금 더 안전한 뒤로가기 경험을 만들 수 있습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

[React] window.matchMedia로 반응형 사이드바 구현하기

[Next.js] next-navigation-guard로 페이지 이탈 방지하기