본문 바로가기
개발/Vue.js

Vue.js Pinia 사용법

by 궁즉변 변즉통 통즉구 2024. 3. 21.
반응형

Vue에서 상태관리 시 많이 활용되고 있는 pinia 사용법에 대해서 알아본다. Vue에서 보통 상태관리에 Vuex가 많이 언급되지만 Pinia의 여러가지 특징으로 많이 활용이 되고 있다.

 

Pinia 특징

Pinia의 특징으로 많이 언급되는 것들은 아래와 같다.

1. 가볍고 직관적인 API

   - Vuex보다 더 가벼우며, 직관적인 API를 제공.
   - Vue.js 3의 Composition API와 함께 사용되어, 개발자가 상태 관리를 더욱 쉽게 할 수 있도록 지원

2. TypeScript와의 호환성 

   - Vuex는 별도의 라이브러리(vuex-module-decorators) 필요

3. 컴포넌트 별 상태 관리

   - 전역 상태 뿐만 아니라, 개별 컴포넌트에서만 필요한 로컬 상태도 관리

4. 성능 최적화

   - Vue3의 reactive 함수를 사용하여 상태를 관리

   - 이를 통해 상태 변화를 실시간으로 추적하고, 반응형으로 처리하여 성능 최적화에 용이

5. getter, action API

   -  Vuex와 유사한 개념인 getter, action과 같은 API를 제공

   - 비동기적, 동기적 로직 모두 action에서 수행함으로 mutations이 없음(불필요한 코드 감소 및 더 간결한 코드 작성)

 

 

Pinia 사용법

pinia와 pinia-plugin-persist 패키지를 설치한다. pinia-plugin-persist에 대한 부분은 하단에서 설명이 되어있다.

npm i pinia pinia-plugin-persist

 

main.js 파일을 아래와 같이 작성한다.

import { createPinia } from 'pinia';
import piniaPersist from 'pinia-plugin-persist';
...
const app = createApp(App);
app.use(createPinia().use(piniaPersist))
...

 

src/stores/todoStore.js 파일을 작성한다. 테스트를 위해 todo 샘플을 pinia를 통해서 작성할 예정이다.

import { defineStore } from "pinia";

const todoStore = defineStore({
  id: "todoStore",
  state: () => ({
    todos: [],
    filter: "all",
    nextId: 0,
  }),
  getters: {
    finishedTodos: (state) => {
      return state.todos.filter((todo) => todo.isFinished);
    },
    unFinishedTodos: (state) => {
      return state.todos.filter((todo) => !todo.isFinished);
    },
    filteredTodos: (state) => {
      if (state.filter === "finished") {
        return state.finishedTodos;
      } else if (state.filter === "unfinished") {
        return state.unFinishedTodos;
      }
      return state.todos;
    },
  },
  actions: {
    reset() {
      this.todos = [];
      this.filter = "all";
      this.nextId = 0;
    },
    addTodo(text) {
      this.todos.push({ text, id: this.nextId++, isFinished: false });
    },
  },
});

export default todoStore;

 

그리고 테스트를 진행할 화면인 TodoView.vue파일을 작성한다.

<template>
  <div style="padding-bottom: 500px; padding-top: 100px">
    <label><input v-model="filter" type="radio" value="all" /> All</label>
    <label
      ><input v-model="filter" type="radio" value="finished" /> Finished</label
    >
    <label
      ><input v-model="filter" type="radio" value="unfinished" />
      Unfinished</label
    >
    <hr />
    <ul>
      <li v-for="todo in filteredTodos" :key="todo.id">
        <input v-model="todo.isFinished" type="checkbox" />
        {{ todo.text }}
      </li>
    </ul>
    <label>
      New Todo:
      <input v-model="newTodoText" type="text" @keypress.enter="addTodo" />
    </label>
    <button :disabled="!newTodoText" @click="addTodo">Add</button>
    <button @click="reset">Reset</button>
  </div>
</template>

<script setup>
import useTodoStore from "@/stores/todoStore";
import { storeToRefs } from "pinia";
import { ref } from "vue";

const todoStore = useTodoStore();
const { filter, filteredTodos } = storeToRefs(todoStore);
const newTodoText = ref("");

function addTodo() {
  if (!newTodoText.value) {
    return;
  }

  todoStore.addTodo(newTodoText.value);
  newTodoText.value = "";
}
function reset() {
  todoStore.reset();
}
</script>

 

실행을 하면 아래 화면에서 pinia를 통해서 todo목록을 관리하는 것을 확인해 볼 수 있다.

 

위 테스트에서 한가지 문제점은 브라우저를 새로고침할 경우 모든 데이터가 없어진다는 것이다. 새로고침으로 인한 Store데이터 Reset 방지를 위해서 패키지 설치 시 언급한 pinia-plugin-persist를 적용할 것이다. 

src/stores/todoStore.js 파일 하단부분에 persist 부분을 추가 작성한다. state의 filter부분은 SessionStorage에 저장하고, todos, nextId는 LocalStorage에 저장하는 샘플이다.

  actions: {
    ...
  },
  persist: {
    enabled: true, // , 전체 state 대상, SessionStorage가 default 저장
    strategies: [
      { storage: sessionStorage, paths: ["filter"] }, // SessionStorage 저장
      { storage: localStorage, paths: ["todos", "nextId"] }, // localStorage 저장 
    ],
  },
});

 

동일하게 실행을 해보면 아래와 같이 LocalStorage, SessionStorage에 각각 데이터가 저장되는 것을 확인할 수 있다. 브라우저를 새로고침해도 데이터가 없어지지 않는다.

 

반응형

댓글