Ch 05. Composable vs Pinia — 언제 무엇을 쓸까
Composable과 Pinia를 배우고 나면 곧 이런 고민이 찾아옵니다. "이 상태는 Composable로 관리해야 할까, Pinia Store로 만들어야 할까?" 두 방식 모두 반응형 상태를 다루지만, 근본적인 차이가 있습니다.
핵심 차이 비교
| 기준 | Composable | Pinia Store |
|---|---|---|
| 공유 범위 | 호출한 컴포넌트마다 독립 인스턴스 | 앱 전체 싱글톤 |
| 영속성 | 컴포넌트 수명과 동일 | 앱이 살아있는 동안 유지 |
| 디버깅 | Vue Devtools 기본 지원 낮음 | Pinia Devtools 완전 지원 |
| 적합한 사례 | API 호출 로직, 로컬 UI 상태 | 로그인 상태, 장바구니, 전역 알림 |
판단 질문
결정하기 어려울 때는 이 질문 하나로 판단할 수 있습니다.
"이 상태를 다른 페이지에서도 유지해야 하나?"
YES라면 Pinia를 선택합니다. 로그인한 사용자 정보, 장바구니 내용, 전역 알림 메시지처럼 페이지를 이동해도 살아있어야 하는 상태가 여기에 해당합니다.
NO라면 Composable로 충분합니다. 특정 페이지에서만 사용하는 API 응답 데이터, 모달의 열림/닫힘 상태, 폼 입력 처리 로직처럼 해당 컴포넌트가 사라지면 함께 사라져도 되는 상태입니다.
두 가지를 조합하는 패턴
Composable이 Pinia Store를 사용하는 패턴도 자주 쓰입니다. API 호출 로직은 Composable로 캡슐화하되, 그 결과를 전역 스토어에 저장하는 방식입니다.
// composables/useAuth.tsexport function useAuth() { const authStore = useAuthStore() async function login(email: string, password: string) { const userData = await $fetch('/api/auth/login', { method: 'POST', body: { email, password } }) authStore.login(userData) } async function logout() { await $fetch('/api/auth/logout', { method: 'POST' }) authStore.logout() } return { login, logout }}
컴포넌트는 useAuth()만 호출하면 됩니다. API 주소나 Pinia Store가 어떻게 동작하는지 알 필요가 없습니다. 로직이 한 곳에 모여 있어 나중에 수정할 때도 편합니다.
이렇게 Composable은 "어떻게 처리할지"를, Pinia는 "무엇을 기억할지"를 각자의 역할로 나누는 것이 실전에서 가장 깔끔한 구조입니다.