티스토리 뷰
최근에 개발중인 프로젝트들은 모두 Vue3의 composition api를 기반으로 하고있다. 다만 아직 typescript가 아닌 javascript를 사용하고, 상태관리는 pinia가 아닌 vuex를 사용 하고 있다. composition api를 사용하면 typescript와 pinia를 사용하는데 있어서 큰 이점을 얻을 수 있다보니 조만간 도입을 시도하려고 한다.
하지만 아직은 아쉽게도 한국어로 된 자료가 많지는 않은 실정이다. 아무래도 한국은 Vue보다는 React의 점유율이 더 높은데다가, 그나마 있는 Vue 자료도 option api로 되어있는 경우가 많다. 어쩔 수 없이 내가 스스로 공부해나가면서 길을 만들어가는 중이다.
src/views/TodoList.vue
템플릿
<template>
<h1>Todo List</h1>
<h3>using interface,pinia</h3>
<div>
<input type="text" placeholder="title" v-model="inputTitle" />
<input type="text" placeholder="name" v-model="inputName" />
<button @click="onClickTodo">Add</button>
</div>
<div v-for="todo in todos" :key="todo.id">
<TodoItem :item="todo" />
</div>
</template>
ts와 pinia를 적용할지라도 템플릿부분은 크게 바뀌지 않는다. 굳이 꼽자면 vuex를 사용했을 때의 템플릿에서 접근할 수 있었던 $store
키워드를 pinia에서는 사용할 수 없다는 점이다.
스크립트
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { useTodoListStore } from '@/stores/todoList';
import { Todo } from '@/types/Todo';
import TodoItem from './TodoItem.vue';
export default defineComponent({
components: { TodoItem },
setup() {
const todoStore = useTodoListStore();
const todos = ref<Todo[]>(todoStore.todos);
const inputTitle = ref<string>('');
const inputName = ref<string>('');
const onClickTodo = (): void => {
todoStore.addTodo({
title: inputTitle.value,
name: inputName.value,
id: todoStore.todos.length + 1,
status: 'yet',
});
inputTitle.value = '';
inputName.value = '';
};
return {
todos,
onClickTodo,
inputTitle,
inputName,
};
},
});
</script>
스크립트부터 이제 변화가 생긴다. 일단 기존<script>
태그를 사용한 것과 달리 타입스크립트에서는 <script lang="ts">
를 사용한다. 또한 기존 export default{}
에서 export default defineComponent({})
를 사용해야 한다.
그리고 composition api에서 변수에 반응성을 부여해주기 위해 사용하는 ref()
함수도 괄호 앞에 제네릭문법을 적용하여 ref<'type'>()
이런 식으로 적어주게 된다. 예를 들어 문자열 데이터를 선언하기 위해서는 ref<string>('Hello')
처럼 적어주면 된다.
src/types/Todo.ts
type Status = 'done' | 'ongoing' | 'yet';
interface Todo {
id: number;
title: string;
name: string;
status: Status;
}
export { Todo, Status };
타입스크립트를 사용하기 위해서 별도의 types
디렉토리를 만들고, interface를 정의하였다.
src/stores/index.ts
import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;
pinia의 index
파일은 단 3줄이면 된다. vuex에서는 각종 모듈을 모두 index
에서 선언해주어야 하는 것과 달리, pinia에서는 각자 따로 선언하는 방식이다. 아래 코드를 보자.
src/stores/todoList.ts
import { defineStore } from 'pinia';
import { Todo, Status } from '@/types/Todo';
export const useTodoListStore = defineStore('todoList', {
state: () => {
return {
todos: [] as Todo[],
};
},
actions: {
addTodo(item: Todo) {
this.todos.push(item);
},
deleteTodo(id: number) {
const idx = this.todos.findIndex((item) => item.id === id);
this.todos.splice(idx, 1);
},
changeStatus(changed: Todo, st: Status) {
this.todos.forEach((item) => {
if (item.id === changed.id) {
item.status = st;
}
});
},
},
});
pinia에서는 defineStore()
라는 함수 안에서 기능을 정의하고 이를 useTodoListStore
라는 이름으로 사용할 수 있다. 그래서 컴포넌트에서 접근할 때는 useTodoListStore.todos
로 state에 접근하고, useTodoListStore.addTodo()
식으로 함수를 사용하면 된다.. 또한 vuex와 다르게 mutations
가 존재하지 않는다. 비동기처리를 actions
에서 수행하고, state
를 변경하기 위해서는 mutations
안의 메소드를 사용한 것과 달리 pinia에서는 actions
에서 비동기 처리와 값의 변경을 모두 처리한다.
'Dev' 카테고리의 다른 글
vue 에서 스크롤 위치 저장 (0) | 2023.03.09 |
---|---|
프로젝트 회고 (0) | 2023.02.18 |
vue 커스텀 디렉티브(custom directive) (0) | 2022.12.05 |
Vue3 타이머 구현 (0) | 2022.11.12 |
css, js를 이용한 룰렛 이벤트 구현(Vue3) (0) | 2022.11.12 |