Search
🍍

Vue3 와 새로운 삼대장 - composition API, TypeScript, pinia

태그
TypeScript
pinia
목차
공식 문서

Composition API 와 Options

왜 저는 vue3 를 택했을까요? 처음에는 그냥 단순히 intelliJ 로 vue 프로젝트를 생성하면 3 였기 때문입니다. 하지만 그 이후 고민되기 시작했죠. composition API 를 쓸 것인지 아니면, Options 를 쓸것인지 말이죠. 이제부터 이 둘의 차이를 알아보고 왜 composition API 를 선택했는지 알려드리겠습니다.

Options

Options API는 Vue 2에서 소개되었습니다. 이 방식에서는 컴포넌트의 데이터, 메서드, 라이프사이클 훅 등을 별도의 옵션으로 정의합니다.
<script> export default { data() { return { message: 'Hello Vue!' }; }, methods: { getMessage() { return this.message; } }, mounted() { console.log('Component is mounted!'); } }; </script> <template> <div>{{ message }}</div> </template>
HTML
복사

Composition API

Composition API 는 Vue 3에서 도입되었습니다. 이 API를 사용하면 모든 리액티브 상태와 함수를 정의하고 구성할 수 있습니다. 위의 Options 의 예시에서 보다 훨씬 간결하지 않나요? 저는 이 간결함에 매료 되었습니다. 코드를 간결하게 작성할 수 있다면 어떤 점에서 이점을 가져갈까요?
<script setup> import { ref, onMounted } from 'vue'; const message = ref('Hello Vue!'); function getMessage() { return message.value; } onMounted(() => { console.log('Component is mounted!'); }); </script> <template> <div>{{ message }}</div> </template>
HTML
복사
컴포넌트 간에 코드를 쉽게 재사용할 수 있습니다.
여러 컴포넌트에서 공통적으로 사용되는 로직을 별도의 함수로 분리하고, 이를 필요한 곳에서 가져와 사용할 수 있습니다.
크고 복잡한 컴포넌트를 더 효과적으로 조직화할 수 있습니다. 로직을 관련된 부분별로 그룹화하고, 서로 다른 관심사를 명확히 분리할 수 있어 코드의 가독성과 유지보수성이 향상됩니다.
로직을 재사용 가능한 함수로 분리함으로써, 각각의 함수를 독립적으로 테스트하기가 더 쉬워집니다. 이는 전체 애플리케이션의 테스트 가능성을 높여줍니다.
Composition API는 코드의 의도를 더 명확하게 만들어줍니다. 각각의 반응성 변수와 메소드가 어떤 목적으로 사용되는지 코드를 통해 쉽게 파악할 수 있습니다.
간결함 외에도 다른 장점이 존재합니다. 바로 타입스크립트와의 조합이 좋다는 점인데요, 타입스크립트를 사용할 때 API 의 구조가 타입 추론과 코드 완성 기능을 더 잘 지원하여 타입 안정성이 향상된다고 합니다. 요 근래 많은 프론트엔드 개발자들이 타입스크립트를 공부한다고 알고 있습니다. 이참에 저도 새로운 문물을 접해보고자 시도해봤습니다.

결론적으로 제가 Composition API 를 선택한 이유는 아래와 같습니다.

간결하다  코드를 쉽게 재사용 할 수 있다.
타입스크립트와 호환성이 좋다.

그럼 TypeScript 는 단순히 Composition API 때문에?

그건 아닙니다. 자바를 주 언어로 삼고 있는 제가 자바스크립트에게 한가지 불만이 있다면 타입을 정확히 명시하지 않는다는 것 이였습니다. 예를 들면 이런거죠.
function add(a, b) { return a + b; }
JavaScript
복사
뭐야 이 약간 불편한 코드는…? 🫠 뭐야 갑자기 int 형이 보고싶어요…
하지만 TypeScript 는 타입 안정성을 보장 해주더군요. 위의 코드를 타입스크립트로 작성하다면 이렇게 됩니다.
function add(a: number, b: number): number { return a + b; }
TypeScript
복사
이제 그나마 괜찮아진 코드… 흡족…

타입 안정성이 보장되면 뭐가 좋을까요?

컴파일 시점에 타입 오류를 잡을 수 있어 런타임 오류를 줄일 수 있습니다.
IDE에서의 자동 완성 및 리팩토링이 용이합니다.
코드에 타입 정보가 포함되어 있어 읽기 쉽고 이해하기 쉽습니다.
이렇게 되면 객체 지향 프로그래밍이 더 쉬워지죠. 그래서 TypeScript 를 선택하게 되었습니다. 이는 Composition API 와 조합이 좋기도 하구요.

상태관리 선택하기 - vuex 냐 pinia 냐 고것이 문제로다.

vue 개발자가 pinia 를 선택한 이유는 뭘까?

vuex 의 mutation

const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { increment(context) { context.commit('increment'); } } }); // 상태 변경 store.commit('increment');
JavaScript
복사
Vuex에서 상태 변경은 mutations 을 통해 이루어집니다. 은 동기적으로만 작동하며, 상태 변경의 추적을 용이하게 합니다. 하지만 비동기적으로 상태변경을 하고 싶다면 어떻게 해야할까요? actions 를 사용해야 하며, 실제 상태 변경은 를 이용해야 한다고 합니다. 그렇다면 pinia 의 경우는 어떨까요?

pinia 는 mutation 이 존재하지 않는다?!

Pinia에서는 mutations 개념이 없으며, 상태 변경은 직접 actions 내에서 수행됩니다. 이는 코드를 더 간결하게 만들며, 비동기 로직을 포함하는 내에서 상태 변경을 직접 수행할 수 있게 합니다.
const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++; } } }); // 상태 변경 const counterStore = useCounterStore(); counterStore.increment();
JavaScript
복사

결론적으로 왜 pinia 가 더 나은건데요?

Pinia는 상태 변경을 위한 별도의 mutations 을 정의할 필요가 없어 코드가 더 간결 해집니다. 때문에 상태 관리 로직을 더 쉽게 이해하고 유지할 수 있습니다.
actions 내에서 직접 상태를 변경할 수 있기 때문에, 동기적 또는 비동기적 로직을 자유롭게 구성할 수 있습니다. 위에서도 말했듯, vuex 에서는 비동기 로직을 처리하기 위해 를 사용해야 하며, 실제 상태 변경은 mutations 을 통해 이루어져야 합니다.
vuex 와 달리 상태 변경을 위해 추가적인 단계(commit)가 필요 없기 때문에 코드의 흐름이 보다 직관적이며 쉽게 추적할 수 있습니다.
TypeScript 와 함께 사용할 때 타입 추론과 코드 작성의 용이성 에서 이점을 가져갑니다. 궁합이 아주 좋다는 소리죠.
그리고 파인애플이 귀엽습니다.

사실 저는 vue2 를 사용해본적이 없어요.

저는 백엔드 개발자이고 그동안 열심히 스프링부트만 공부했기 때문에 vue2 + vuex 조합을 접해볼 일이 없었습니다. 때문에 비교가 불가능하죠. 제가 무언가를 선택할때의 기준은 ‘간결함’ 과 ‘안정성’ 인것 같습니다. 그래야 코드의 유지보수와 분리가 쉬워지기 때문이죠. 그래서 타입스크립트의 도입을 우선적으로 고민했고, 그러다 보니 composition API 와 pinia 를 선택하게 된 것 같습니다. 아무래도 짧은 시간에 배워야 했으니까요 하지만 많은 사람들이 추천하고 뷰 창시자 마저 추천하는 것을 보니 잘 선택한듯 합니다.