
Composition API를 제대로 쓰려면 Composable과 Pinia를 어떻게 나눌지부터 감이 잡혀야 한다.
Composable = 재사용 가능한 Composition API 함수
Vue 3에서 setup() 안에 마구 섞여 있던 로직을 역할별로 분리해 별도 함수로 뽑아낸 것
예를 들어 강의 목록 화면에 있는:
useCourses() 같은 함수로 빼서, 다른 컴포넌트에서도 그대로 재사용할 수 있게 만드는 패턴재사용성
역할 분리
테스트 용이
유지보수 편의
한 줄로 정리하면:
Composable은 Vue에서 비즈니스 로직을 UI에서 떼어낸, 독립적인 재사용 모듈이라고 보면 된다.
리팩토링 전 강의 목록 화면은 대충 이런 느낌이다.
onMounted 안에서 직접 fetchCourses() 호출computed로 정의localFavoriteIds)를 컴포넌트 로컬 상태로 직접 관리이 구조의 문제:
작은 예제 수준에서는 버틸 수 있지만, 실전에서는 바로 한계가 드러나는 구조다.
리팩토링 포인트는 로직을 두 축으로 나누는 것:
Composable (예: useCourses)
Pinia Store (예: useCourseStore)
그리고 화면 컴포넌트는 이렇게 단순해진다.
구조를 한 번 더 정리하면:
Composition API의 장점을 그대로 살린 구조라고 보면 된다.
useCourses가 맡는 역할useCourses() 같은 Composable이 하는 일은 보통 이렇게 정리된다.
강의 목록 상태 관리
courses, loading, error 같은 상태데이터 로딩
fetchCourses() 내부에서 API 호출onMounted 시 자동으로 한 번 호출검색/필터링 로직
searchKeyword, levelFilter 등의 값에 따라filteredCourses를 computed로 계산화면에 종속되지 않는 로직만 모아두기
이렇게 만들어두면 다음 화면들에서 전부 재사용 가능하다.
핵심은 UI와 연결되는 부분만 View에 남기고, 나머지 비즈니스 로직은 useCourses로 몰아넣는 것이다.
Pinia는 “앱 전역에서 쓰는 상태”를 모아두는 창고 같은 역할을 한다.
Composable이 “기능 로직”이라면
Pinia는 “앱 전체에서 공유하는 데이터”라고 보는 게 이해하기 쉽다.
강의 예제를 기준으로 Pinia에서 관리하는 값 예시:
favoriteIdspreferredLevellastViewedCourseId이 값들의 공통점:
따라서:
Composable은 각 기능별 로직 단위,
Pinia는 여러 기능에서 공통으로 쓰는 전역 상태라고 이해하면 된다.
이렇게 구조를 나누면 실제 개발에서 체감되는 장점이 꽤 크다.
const { courses, filteredCourses, fetchCourses } = useCourses() 같은 식으로 받아서 템플릿에 바인딩만 해 주면 된다.→ 화면 파일이 “화면 코드”만 남아서 훨씬 읽기 편해진다.
useCourses()만 다시 호출하면 된다.useAuth(), useNotification(), useForm() 등 공통 기능을 계속 쌓아갈 수 있다.→ “어디서는 즐겨찾기 추가됐는데, 다른 곳에는 안 반영되는” 식의 꼬임을 줄일 수 있다.
useCourses와 courseStore는 그대로 둘 수 있다.이 세 가지 역할을 명확하게 나누면,
페이지가 늘어나도 구조가 깨지지 않고,
로직 재사용과 유지보수가 훨씬 편해진다.