홈으로 돌아가기

Vue에서 뒤로 가기 버튼: 올바른 구현

Vue.js 애플리케이션에서 뒤로 가기 버튼의 올바른 구현을 위한 기술 가이드. router.push() 사용 오류 분석, 엣지 케이스 솔루션 제안 및 fallback과 확인이 포함된 범용 컴포넌트.

Vue에서 뒤로 가기 버튼: 함정과 해결책
Advertisement 728x90

# # Vue에서 '뒤로 가기' 버튼을 제대로 구현하는 방법: 개발자를 위한 기술 가이드

Vue.js 애플리케이션에서 '뒤로 가기' 버튼을 구현하는 일은 간단해 보이지만, 실제로는 심각한 네비게이션 및 브라우저 히스토리 문제를 야기합니다. 많은 개발자들이 기존 히스토리 스택을 이동하도록 설계된 메서드 대신 router.push()를 잘못 사용합니다. 이로 인해 중복 항목이 생성되고, 브라우저의 뒤로 가기 버튼 동작이 깨지며, 무한 전환 루프가 발생합니다. 이 글은 엣지 케이스와 사용자 경험을 고려해 '뒤로 가기' 버튼을 올바르게 구현하는 기술적으로 정확한 가이드를 제공합니다.

왜 router.push()가 '뒤로 가기'가 아닌가

router.push() 메서드는 브라우저 히스토리에 새 항목을 추가합니다. 이는 이전에 방문한 적이 있는 라우트라도 앞으로 새 라우트로 이동하는 데 적합합니다. 반대로 router.back()router.go(-1)은 새 항목을 만들지 않고 기존 히스토리 스택 내에서 포인터를 이동할 뿐입니다.

'뒤로 가기' 버튼에 router.push()를 사용하면 실제로는 앞으로 이동을 시뮬레이션하며 뒤로 가는 척하는 꼴이 됩니다. 이로 인해 다음과 같은 순서가 발생합니다:

Google AdInline article slot
  • 사용자: 홈 → 상품 목록 → 상품 A
  • 당신의 '뒤로 가기' 버튼 클릭 (router.push('/list'))
  • 히스토리: 홈 → 상품 목록 → 상품 A → 상품 목록 (중복)

이제 사용자가 브라우저의 뒤로 가기 버튼을 누르면 '홈'이 아닌 '상품 A' 페이지로 돌아갑니다. 버튼을 다시 누르면 push가 또 실행되어 순환이 계속됩니다.

Vue Router의 주요 네비게이션 메서드

Vue Router는 히스토리를 관리하는 세 가지 핵심 메서드를 제공합니다:

  • router.push(location) — 히스토리에 새 항목 추가.
  • router.replace(location) — 현재 항목을 대체하며 새 항목 추가 안 함.
  • router.back() / router.go(-1) — 기존 히스토리를 뒤로 이동.

UI의 '뒤로 가기' 버튼에는 유일하게 올바른 선택router.back() 또는 router.go(-1)입니다. 이들은 브라우저 버튼의 동작과 완벽히 일치하며 스택 무결성을 해치지 않습니다.

Google AdInline article slot

엣지 케이스 처리: 히스토리가 없을 때

실제로는 사용자가 외부 링크, 페이지 새로고침, 탭 닫기 후 직접 페이지에 들어오는 경우가 많습니다. 이런 상황에서 히스토리 스택이 비어 있거나 한 항목만 있을 수 있습니다. router.back()을 호출해도 오류는 발생하지 않지만 아무 일도 일어나지 않아 사용자가 곤란해집니다.

이를 피하려면 대체 라우트(fallbackRoute)를 제공하세요. 로직은 뒤로 이동이 가능한지 확인하고, 불가능하면 안전한 라우트(예: 홈 페이지나 상위 섹션)로 리다이렉트해야 합니다.

범용 '뒤로 가기' 버튼 컴포넌트

모든 필수 시나리오를 지원하는 프로덕션 레디 컴포넌트입니다:

Google AdInline article slot
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute, type RouteLocationRaw } from 'vue-router'

const props = defineProps<{
  fallbackRoute?: RouteLocationRaw
  beforeNavigate?: () => boolean | Promise<boolean>
  beforeRouterPush?: () => void
}>()

const router = useRouter()
const route = useRoute()

const isSamePage = computed<boolean>(() => {
  const fromRoute = router.options.history.state?.back

  if (!fromRoute || typeof fromRoute !== 'string') return false

  const currentPrefix = route.path.split('/')[1]
  const fromPrefix = fromRoute.split('/')[1]

  return currentPrefix === fromPrefix
})

const goBack = async () => {
  if (props.beforeNavigate) {
    const shouldProceed = await props.beforeNavigate()
    if (!shouldProceed) return
  }

  if (props.beforeRouterPush) {
    props.beforeRouterPush()
    return
  }

  if (isSamePage.value) {
    router.back()
  } else if (props.fallbackRoute) {
    void router.push(props.fallbackRoute)
  } else {
    void router.push({ name: 'home' })
  }
}
</script>

<template>
  <q-btn
    icon="arrow_back"
    @click="goBack"
    aria-label="Onzad"
  />
</template>

이 컴포넌트는 여러 작업을 한 번에 해결합니다:

  • 떠나기 전 확인 지원 (예: 임시 저장)
  • URL 접두사로 내부/외부 전환 구분
  • 대체 라우트 제공
  • 필요 시 로직 완전 오버라이드 허용

핵심 포인트

  • '뒤로 가기' 버튼에 router.push() 사용 금지 — 브라우저 히스토리 모델을 위반합니다.
  • 직접 접근 케이스에 항상 대체 동작 제공.
  • 전환 컨텍스트 확인: 섹션 내 반환과 외부로부터는 다른 로직 필요.
  • 비동기 훅으로 네비게이션 취소 지원 — 폼과 에디터에 필수.
  • 브라우저 기본 뒤로 가기 버튼과 동작 동기화 — 사용자가 차이를 느끼지 못하게.

— Editorial Team

Advertisement 728x90

다음 읽기