dev.syw

페이지 전환을 위한 라우터와 전역 상태 관리 Pinia 입문.

Vue Router 와 Pinia 맛보기

컴포넌트만으로 작은 화면은 만들 수 있지만, 실제 앱에는 여러 페이지 전환여러 컴포넌트가 공유하는 상태가 필요합니다. 전자는 공식 라우터 Vue Router, 후자는 공식 상태 관리 라이브러리 Pinia 가 담당합니다. 이번 마지막 강의에서 두 도구의 기본을 맛봅니다.

학습 목표

  • Vue Router로 경로와 컴포넌트를 매핑하고 페이지를 전환한다.
  • router-link·useRoute·useRouter 의 역할을 안다.
  • Pinia 스토어를 정의하고 컴포넌트에서 사용한다.
  • 언제 라우터·Pinia를 도입해야 하는지 판단한다.

Vue Router 설정

경로마다 보여줄 컴포넌트를 정의하고, 앱에 등록합니다.

// router.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/user/:id', component: () => import('./views/User.vue') }, // 지연 로딩
];

export const router = createRouter({
  history: createWebHistory(),
  routes,
});
JavaScript
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import { router } from './router';

createApp(App).use(router).mount('#app');
JavaScript

라우터 표시와 이동

<router-view> 는 현재 경로에 맞는 컴포넌트가 그려지는 자리, <router-link> 는 페이지 이동 링크입니다.

<!-- App.vue -->
<template>
  <nav>
    <router-link to="/"></router-link>
    <router-link to="/about">소개</router-link>
  </nav>
  <router-view />
</template>

💡 TIP<router-link> 는 새로고침 없이 화면만 바꿉니다(SPA). 일반 <a href> 와 달리 페이지 전체를 다시 받지 않아 빠릅니다.

useRoute / useRouter

컴포넌트 안에서 현재 경로 정보를 읽거나 코드로 이동할 때 씁니다.

<script setup>
import { useRoute, useRouter } from 'vue-router';

const route = useRoute();    // 현재 경로 정보 (읽기)
const router = useRouter();  // 이동 명령 (쓰기)

console.log(route.params.id);   // /user/:id 의 id

const goHome = () => router.push('/');
</script>
  • useRoute() — 현재 경로의 params·query 등을 읽을 때.
  • useRouter()push·back 등 코드로 이동시킬 때.

Pinia 스토어 정의

여러 컴포넌트가 공유하는 상태(로그인 정보, 장바구니 등)는 Pinia 스토어에 둡니다.

// stores/counter.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0);                          // state
  const double = computed(() => count.value * 2); // getter
  const increment = () => count.value++;          // action
  return { count, double, increment };
});
JavaScript

<script setup> 스타일과 똑같이 ref·computed·함수로 작성한다는 점이 직관적입니다.

// main.js 에 등록
import { createPinia } from 'pinia';
createApp(App).use(createPinia()).use(router).mount('#app');
JavaScript

Pinia 스토어 사용

컴포넌트에서 스토어를 호출하면 어디서든 같은 상태를 공유합니다.

<script setup>
import { useCounterStore } from './stores/counter';

const counter = useCounterStore();
</script>

<template>
  <p>{{ counter.count }} (×2 = {{ counter.double }})</p>
  <button @click="counter.increment()">증가</button>
</template>

⚠️ 주의 — 스토어 속성을 const { count } = counter 로 분해하면 반응성이 끊깁니다. 분해가 필요하면 storeToRefs(counter) 를 쓰세요. (단, action 함수는 그냥 분해해도 됩니다.)

언제 쓰나

도구도입 시점
Vue Router페이지(URL)가 여러 개로 나뉘는 앱(SPA)
Pinia멀리 떨어진 컴포넌트들이 같은 상태를 공유해야 할 때

작은 앱에서 props/emit 으로 충분하다면 굳이 Pinia를 먼저 도입할 필요는 없습니다. props 전달이 너무 깊어지거나 여기저기 흩어진 상태가 꼬이기 시작할 때 도입하는 것이 적절합니다.

요약

  • Vue Router는 경로–컴포넌트 매핑으로 SPA 페이지 전환을 만든다.
  • <router-link>·<router-view>·useRoute·useRouter 가 핵심 도구다.
  • Pinia는 defineStore 로 전역 상태(state·getter·action)를 정의한다.
  • 라우터는 다중 페이지, Pinia는 공유 상태가 필요해질 때 도입한다.

연습문제

  1. //about 두 경로를 라우터에 등록하고 <router-link> 로 오가는 메뉴를 만들어 보세요.
  2. /user/:id 경로를 만들고, useRouteid 를 읽어 화면에 표시해 보세요.
  3. useCounterStore 를 만들어 두 개의 다른 컴포넌트가 같은 count 를 공유하는지 확인해 보세요.
  4. 스토어 값을 분해 할당할 때 storeToRefs 가 필요한 이유를 설명해 보세요.

힌트 — 코드 이동은 router.push('/about'). const { count, double } = storeToRefs(counter) 로 반응성을 지킨 채 분해합니다.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

Vue.js” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.