Pinia vs Vuex

itbuddy·2024년 9월 1일

관심 기술

목록 보기
1/2
post-thumbnail

pinia

Pinia 는 Vue.js 애플리케이션의 구성 요소에서 반응형 데이터와 상태를 관리하고 저장하는 데 도움이 되는 새로운 상태 관리 라이브러리입니다. Pinia는 Vue 핵심 팀원 중 한 명인 Eduardo San Martin Morote가 만들었습니다.

피니아는 새로운 반응성 시스템을 사용하여 직관적이고 완전한 유형이 적용된 상태 관리 시스템을 구축합니다.

라이브러리에 도입된 새로운 기능은 Pinia의 추천에 기여하는 요인 중 하나입니다. 전반적으로 Pinia는 가볍고 복잡하지 않으며 마스터하기 쉽습니다. Vue 3 및 Vue 2에서 프로그래밍을 다재다능하게 만들 수 있는 모든 것을 갖추고 있습니다. 따라서 Pinia를 사용해 볼 수 있는 이상적인 기회입니다.

Pinia와 Vuex의 차이점 중 하나는 Pinia가 "모듈식 설계"라는 것입니다. 즉, 여러 개의 매장을 갖도록 구축된 반면 Vuex는 매장이 하나뿐입니다. 이러한 매장 내부에는 하위 모듈을 둘 수 있습니다. 그 외에도 Pinia는 이러한 각 모듈을 필요한 경우 매장에서 직접 구성 요소로 가져올 수 있습니다.

pinia 특징

  1. 모듈식 디자인 : 보다 객체지향적으로 코딩이 가능
  2. Full Devtool Support : 요즘 기본사양
  3. 직관적 : mutation이 없어서 비교적 필요없다고 생각되는 코드의 작성을 하지 않음
  4. 확장성 : 트랜젝션이나 로컬스토리지 동기화 같은 플러그인 제공
  5. Typescript support : 요즘 기본사양
    6. 가벼운 라이브러리 : 1KB -> ( Gemini 하루시네이션... )
  6. 가벼운 라이브러리 : 21.5kB(Minified), 7.7kB(Minified + Gzipped)

VUEX vs PINIA in code

VUEX

import Vue from 'vue'
import Vuex, { ActionTree, GetterTree, MutationTree } from 'vuex'
import { filterTypes, State, TodoItem } from './types'

Vue.use(Vuex)

const state: State = {
  todos: [],
  activeFilter: filterTypes[0],
}

const getters: GetterTree<State, any> = {
  allTodos: state => state.todos,
}

const mutations: MutationTree<State> = {
  addTodo(state, txt: string) {
    if (state.todos.map(todo => todo.txt).indexOf(txt) === -1) {
      state.todos.push({
        txt,
        done: false,
      })
    }
  },
  toggleTodo(_state, todo: TodoItem) {
    todo.done = !todo.done
  },
  deleteTodo(state, todo: TodoItem) {
    state.todos.splice(state.todos.indexOf(todo), 1)
  },
  selectFilter(state, {filter}) {
    state.activeFilter = filter
  },
}

const actions: ActionTree<State, State> = {
  selectFilter({commit}, filter) {
    commit('selectFilter', { filter })
  },
}

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
})

// 사용
   import Vue from 'vue'
import Component from 'vue-class-component'
import { Mutation, State } from 'vuex-class'
import Todo from './components/Todo'
import TodoFilter from './components/TodoFilter'
import store from './store/index'
import { TodoItem } from './store/types'
import WithRender from './templates/app.html'

@WithRender
@Component({
  components: {
    Todo, TodoFilter,
  },
})
export default class App extends Vue {
  name: string = 'App'
  input: string = ''
  filters: any = {
    ALL: (todos: TodoItem[]) => todos,
    ACTIVE: (todos: TodoItem[]) => todos.filter((todo: TodoItem) => !todo.done),
    COMPLETED: (todos: TodoItem[]) => todos.filter((todo: TodoItem) => todo.done),
  }

  @State todos: TodoItem[]
  @State activeFilter: string
  @Mutation toggleTodo: (todo: TodoItem) => void // Best would be if this could derive the type automatically
  @Mutation deleteTodo: any

  get filteredTodos() {
    return this.filters[this.activeFilter](this.todos)
  }

  addTodo(): void {
    if (!this.input.trim().length) {
      return
    }

    this.$store.commit('addTodo', this.input.trim())
    this.input = ''
  }
}

PINIA

import { computed, ref } from 'vue';
import { defineStore } from 'pinia';
import type { ITodo } from '@/interfaces';

function toggleProp(prop: 'important' | 'done', id: string, todo: ITodo) {
  return todo.id === id ? { ...todo, [prop]: !todo[prop] } : todo;
}

export const useTodoStore = defineStore('todo', () => {
  const todos = ref<ITodo[]>([]);

  function addTodo(todo: ITodo) {
    todos.value.push(todo);
  }

  function removeTodo(id: string) {
    todos.value = todos.value.filter((todo: ITodo) => todo.id !== id);
  }

  function toggleDone(id: string) {
    todos.value = todos.value.map((todo) => toggleProp('done', id, todo));
  }

  function toggleImportant(id: string) {
    todos.value = todos.value.map((todo) => toggleProp('important', id, todo));
  }

  const doneTodosCount = computed(() => todos.value.filter((todo) => todo.done).length);
  const importantTodosCount = computed(() => todos.value.filter((todo) => todo.important).length);
  const activeTodosCount = computed(() => todos.value.filter((todo) => !todo.done).length);

  return {
    addTodo,
    removeTodo,
    toggleDone,
    toggleImportant,
    doneTodosCount,
    importantTodosCount,
    activeTodosCount,
    todos
  };
});

// 사용

<script setup lang="ts">
import { Input, List, ListItem, Typography } from 'ant-design-vue';
import { ref } from 'vue';
import { useTodoStore } from '@/stores/todo';
import { v4 as uuidv4 } from 'uuid';
import CloseCircleOutlined from '@ant-design/icons-vue/lib/icons/CloseCircleOutlined';
import CheckOutlined from '@ant-design/icons-vue/lib/icons/CheckOutlined';
import ExclamationOutlined from '@ant-design/icons-vue/lib/icons/ExclamationOutlined';

const field = ref('');
const store = useTodoStore();

function createTodo(text: string) {
  return { text, id: uuidv4(), done: false, important: false };
}

function handleAddTodo() {
  const todo = createTodo(field.value);
  store.addTodo(todo);

  field.value = '';
}
</script>


둘의 코드상 차이점

  1. pinia는 mutation이 없다.
  2. store를 사용할때의 코드가 간편하다.
    • vuex
      • this.$store.commit('addTodo', this.input.trim())
    • pinia
      • store.addTodo(todo);
      • <List bordered :data-source="store.todos">
  3. pinia는 store/index.ts 가 필요 없다.

후기

위 3가지의 차이점만 봐도 pinia를 사용하면 vuex보다 직관적인 코드의 작성이 가능하다고 생각됩니다.
1년 전부터 알고있던 라이브러리지만 코드로 직접 비교해서 보니까 도 다르군요


Ref

bundlephobia 번들링 사이즈
https://www.telerik.com/blogs/vue-js-state-management-pinia-vs-vuex
https://github.com/johnygomez/vue-vuex-typescript-example
https://github.com/kamenivskyi/todo-pinia-example

profile
프론트도 조금 아는 짱구 같은 서버 프로그래머

0개의 댓글