페이지 전환을 위한 라우터와 전역 상태 관리 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,
});
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import { router } from './router';
createApp(App).use(router).mount('#app');
라우터 표시와 이동
<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 };
});
<script setup> 스타일과 똑같이 ref·computed·함수로 작성한다는 점이 직관적입니다.
// main.js 에 등록
import { createPinia } from 'pinia';
createApp(App).use(createPinia()).use(router).mount('#app');
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는 공유 상태가 필요해질 때 도입한다.
연습문제
/와/about두 경로를 라우터에 등록하고<router-link>로 오가는 메뉴를 만들어 보세요./user/:id경로를 만들고,useRoute로id를 읽어 화면에 표시해 보세요.useCounterStore를 만들어 두 개의 다른 컴포넌트가 같은count를 공유하는지 확인해 보세요.- 스토어 값을 분해 할당할 때
storeToRefs가 필요한 이유를 설명해 보세요.
힌트 — 코드 이동은
router.push('/about').const { count, double } = storeToRefs(counter)로 반응성을 지킨 채 분해합니다.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Vue.js” 강좌에 대한 댓글입니다.