(스토어)Vuex vs Pinia, Vue Store 비교

안녕하세요. 오늘은 오랜만에 Vue에 대한 글을 써보려 합니다. 예전부터 쓰려고 했던 주제인데 클라우드 자격증을 준비하면서 클라우드 쪽 포스팅에 집중하다보니 포스팅이 예정보다 조금 늦어졌습니다.

MVC 패턴 대 Flux 패턴

먼저 매장과 관련된 디자인 패턴인 플럭스 패턴의 배경을 살펴보자. Flux 패턴이 나오기 전에는 MVC 패턴이 주로 사용되었습니다.

MVC 패턴


사용자가 View에서 이벤트를 action으로 트리거하면 Controller로 전달되고 로직 처리 후 Model에 접근하여 데이터를 수정하고 View에 데이터가 업데이트되었음을 ​​알립니다. 또한 데이터 수정 없이 뷰만 변경되는 경우에는 컨트롤러가 모델을 통하지 않고 뷰를 직접 조작할 수 있고, 데이터가 중간 로직 없이 직접 요청되면 모델이 뷰에서 데이터를 요청할 수 있다.

그러나 MVC 패턴은 복잡성 증가했다, 양방향 데이터 흐름내가 가지고 있기 때문에 문제가 발생했습니다. 화면이 전환될 때마다 어디에서 변화가 일어났나요? 데이터 추적 관리가 어려움불이익이 발생했습니다.

플럭스패턴

플럭스 패턴은 MVC 패턴의 단점을 극복하기 위해 나온 디자인 패턴입니다. 플럭스 패턴의 경우 단방향 데이터 흐름~을 통해애플리케이션 복잡성 감소 및 단순화단방향 데이터 흐름을 통해 관리하기 쉬운 데이터 추적장점이 하나 있습니다.


Flux 패턴에서는 Action, Dispatcher, Store, View의 네 부분으로 나누어 관리합니다.

지정 역할
행동 이벤트에 가입 이벤트 발생 시 Action 객체를 생성하고 Dispatcher에 전달합니다. 작업 만들기역할을하다.
디스패처 Action 객체의 중앙 허브 역할 type 속성의 값을 보고 어떤 조치를 취해야 하는지 Store에 문의하십시오.하다.
스토어 콜백을 등록하는 데 사용됩니다. 상점에 작업 배포그렇게 하는 역할을 합니다.
가게 스테이트풀 스토어. 상태를 변경하는 논리또한 포함합니다.
보다 매장 상황에 따라 화면에 렌더링역할을하다.

오늘은 Vue에서 많이 사용하는 Vuex와 pinia에 대해 설명드리겠습니다.

(구성 API 기반 sciprt 설정 스크립트를 사용하는 환경가정하고 설명하겠습니다.)

뷰엑스

vuex는 vue에 있습니다 가장 많이 사용매장 관련 라이브러리입니다. 옵션 API 기반사용 된 API는

  • 상태
  • 게터
  • 돌연변이
  • 행위

있습니다.

https://v3.vuex.vuejs.org/kr/

Vuex는 무엇입니까? | 뷰엑스

Vuex는 무엇입니까? Vuex는 Vue.js 애플리케이션을 위한 상태 관리 패턴 + 라이브러리입니다. 애플리케이션의 모든 구성 요소에 대한 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를 유지합니다.

v3.vuex.vuejs.org

기본 설정

기본 설정은 main.js 또는 main.ts 파일아래와 같이 설정할 수 있습니다.

import { createApp } from "vue";
import App from "./App.vue";
import router from "@/routes";
import {store} from "@/store"
import eventBus from "@/utils/bus";

createApp(App)
  .use(store)
  .use(router)
  .provide('$bus',eventBus)
  .mount("#app");

상태

state는 Store에서 관리하는 상태입니다. 상점에서는 다음과 같이 정의합니다.

import {createStore} from "vuex";

export const store = createStore({
    state : {
    user: {},
    item: {},
    list: ()
  },
})

실제 화면에서 상태 값을 참조하고 싶을 때는 다음과 같이 사용합니다.

아마도 옵션 API를 이용하신 분들은 스토어 접속 시 아래와 같이 useStore로 접속하지 않으셨습니다. this.$store.state접근했을 것이다 구성 API~에 이 없어졌기 때문에 다음과 같이 useStore API를 사용하여 상점에 액세스하십시오. 컴포지션 API에서도 Vuex 도우미도 사용할 수 없습니다.하다.

<template>
  <div>
    <UserProfile>
      <template #username>{{ userInfo.id }}</template>
      <template #time>
        <span>{{ `Joined ${userInfo.created}` }}, </span>
      </template>
      <template #karma>
        <span>{{ userInfo.karma }}</span>
      </template>
    </UserProfile>
  </div>
</template>

<script setup lang="ts">
import { useStore } from "vuex"

const store = useStore()
const userInfo = computed(() => store.state.user)
</script>

게터

상태에 대해 계산된 속성사용하고 싶다면 게터당신이 사용할 수있는 . Vue의 관점에서 여기에 계산된 적합한다고 볼 수 있습니다. 예제 코드에서는 계산된 속성으로 정의해야 하는 소스가 없어서 구현하지 않았지만 예제로 사용하면 아래와 같은 형태로 정의가 됩니다.

import {createStore} from "vuex";

export const store = createStore({
    getters : {
    	doubleCnt(state) {
        	return state.cnt*2;
        }
    }
  },
})

그리고 실제 호출하는 부분은 아래와 같은 형태로 사용됩니다.

<template>
  <div>
    {{ cnt }}
  </div>
</template>

<script setup lang="ts">
import { useStore } from "vuex"

const store = useStore()
const count = store.getters.doubleCnt;
</script>

게터의 경우에도 다른 getters API를 호출하여 계산된 속성 값을 반환합니다.당신은 할 수 있습니다. 다시 말해서, 반환 값은 상태가 아닌 게터가 될 수 있습니다.도 있다고 합니다.

아래 코드에서 getCnt는 상태 카운트 값을 반환하고 doubleCnt는 getCnt라는 getter를 참조하여 계산된 속성 값을 반환합니다.

import {createStore} from "vuex";

export const store = createStore({
    getters: {
        doubleCnt: (state, getters) => {
            return getters.getCnt*2;
        },
        getCnt: (state) => {
            return state.count;
        }
	}
})

돌연변이

돌연변이는 상태의 상태 값을 변환하는 데 사용됩니다. 돌연변이 동기 로직 정의해주는 기능이 있습니다. 즉 말하자면, 순차적으로 상태 변경이렇게 하면 상태 변경을 쉽게 추적할 수 있습니다. 여러 구성 요소에서 상태를 변경하려면 커밋을 사용하여 명시적으로 변형 호출해야만한다.

변이 정의 부분은 다음과 같이 정의됩니다. 제 경우에는 뮤테이션과 액션의 경우 네이밍 컨벤션이 스네이크 케이스그것을 가져 갔다

import {createStore} from "vuex";

export const store = createStore({
    mutations: {
      SET_USER(state, user) {
        state.user = user
      },
      SET_ITEM(state, item) {
        state.item = item
      },
      SET_LIST(state, list) {
        state.list = list
      }
  },
})

그리고 화면이나 작업에서 직접 변형을 호출하는 대신 commit이라는 API를 통해 호출됨해야만한다. 아마도 이것은 단방향 흐름을 유지하기 위해 커밋을 통해서만 Vuex의 상태 변경이 이루어지도록 설계되었을 것입니다.

첫 번째 인수로 호출할 돌연변이의 이름, 두 번째 인수의 값으로 전달할 데이터들어갑니다. 두 번째 인수 값의 경우 유효 탑재량 양식으로 넘어 갑시다. 페이로드는 객체 형태로 전달할 수도 있습니다.하다.

<script setup lang="ts">
import { useStore } from 'vuex';

const userInfo = computed(()=> store.state.storeModule.user)

const store = useStore()

store.commit('SET_USER',userInfo)
</script>

행위

돌연변이가 동기 상태 변경을 처리하는 경우 작업은 비동기 상태 변경입니다.커버. setTimeout()동일한 간격 또는 axios를 통한 http 통신 처리필요한 경우. 뮤테이션의 상태 값을 추적하기 위해 상태 값 변경은 커밋을 통해서만 이루어지며 이는 액션에서도 마찬가지입니다. 작업에서 상태를 변경하려면 커밋 내부 작업을 통해 돌연변이 호출해야만한다.

정의 부분을 살펴보겠습니다. 아래와 같이 중간에 commit을 통해 mutations의 기능이 호출되는 부분을 볼 수 있습니다.

첫 번째 인수로 문맥입력되어 있으며, 현재 아래 코드의 경우 Destructuring 할당을 통한 커밋만 선언 및 사용두 번째 인수에서 디스패처에 전달된 데이터가다 유효 탑재량 형태로 전달됩니다.

import {createStore} from "vuex";

export const store = createStore({
    actions: {
        async FETCH_USER({commit}, name) {
          const response = await fecthUserInfo(name)
          commit('SET_USER',response.data)
          return response
      },
        async FETCH_ITEM({commit}, id) {
          const response = await fetchCommentItem(id)
          commit('SET_ITEM', response.data)
          return response
      },
        async FETCH_LIST({commit}, pageName) {
          const response = await fetchList(pageName)
          commit('SET_LIST', response.data)
          return response
      }
  }
})

실제 사용 중 디스패치 API를 통해 호출됨하다. Dispatch를 사용하면 작업 내에서 커밋을 호출하여 비동기적으로 데이터를 관리할 수 있습니다.

import UserProfile from '@/components/store/UserProfile.vue';

import { useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { computed } from "vue"

const route = useRoute()
const store = useStore()

const userName = route.params.id

const userInfo = computed(()=> store.state.storeModule.user)

store.dispatch('FETCH_USER', userName)

지금까지 Vuex에 대해 살펴보았습니다. 이제 Vuex를 대체한 pinia를 살펴보겠습니다.

https://pinia.vuejs.org/

피니아 | Vue.js를 위한 직관적인 스토어

직관적이고 안전하며 가볍고 유연한 Store for Vue

pinia.vuejs.org

Pinia는 Vue 핵심 팀의 구성원인 Edurado San Martin Morote가 개발했습니다. Vue2와 Vue3 버전 모두 호환됩니다.

기본적으로 Pinia Option API 및 Composition API 유형 모두 지원하다.

기본 설정

기본 설정은 동일합니다 main.js 또는 main.ts 파일아래와 같이 설정합니다.

import { createApp } from "vue";
import App from "./App.vue";
import router from "@/routes";
import { createPinia } from "pinia";
import eventBus from "@/utils/bus";

const store = createPinia();

createApp(App)
  .use(store)
  .use(router)
  .provide('$bus',eventBus)
  .mount("#app");

옵션 API 양식

Option API 형태를 보면 Vuex와 가장 큰 차이점은 돌연변이가 사라졌다는 사실안돼.

Vuex에서는 commit in action을 통해 돌연변이를 호출하여 상태를 변경했습니다. 그러나 pinia의 경우 돌연변이가 사라집니다. 액션에서 직접 상태로 변경할수있다. 따라서 작업은 더 이상 컨텍스트를 받을 필요가 없습니다.

그리고 생성 부분 createStore~ 아니다 defineStore로 변경 네임스페이스를 첫 번째 인수로 사용받다, 두 번째 인수에 저장구현하다.

import {defineStore} from "pinia";

const useListStore = defineStore("list",() => {
    actions: {
        async fetchUser(name) {
          const response = await fecthUserInfo(name)
          state.user = response.data
      },
        async fetchItem(id) {
          const response = await fetchCommentItem(id)
          state.item = response.data
      },
        async fetchListItem(pageName) {
          const response = await fetchList(pageName)
          state.lsit = response.data
      }
  }
})

구성 API 양식

Composition API 양식이 간소화되었습니다. Composition API를 사용하듯이 vue 화면에서 props, computed, method를 사용할 수 있습니다.

과거에 상태 같은 경우 반응형 ref로 선언된 반응형 변수로 선언 행위~이다 행동 양식, 게터~이다 계산에 해당하다.

평소 저장소를 사용하면서 불편한 점은 Flux 패턴에 따라 각 프레임워크에 사용되는 별도의 이름과 구조를 외워야 하는데 pinia를 사용하여 스토어 구조에 대한 이해 없이 Composition API만 이해한다면 바로 사용할 수 있다는 점이 저에게는 큰 장점으로 다가온 것 같습니다.

import { fecthUserInfo, fetchList, fetchCommentItem } from "@/api";
import { ResponseData } from "@/types";
import { defineStore } from "pinia";
import { Ref, ref } from "vue";

const useListStore = defineStore("list", () => {
  const user: Ref<ResponseData> = ref(());
  const item: Ref<ResponseData> = ref(());
  const list: Ref<ResponseData> = ref(());

  const setUser = async (name: string | string()) => {
    const response = await fecthUserInfo(name);
    user.value = response.data;
  };
  
  const setItem = async (id : string | string()) => {
    const response = await fetchCommentItem(id);
    item.value = response.data;
  }
  
  const setList = async (pageName : string | string()) => {
    const response = await fetchList(pageName);
    list.value = response.data;
  }

  return {user, item, list, setUser, setItem, setList}
});

export default useListStore;

가게를 참조하십시오

스토어를 지칭하는 부분에서 스토어를 가져와 일반 변수를 사용하듯이 사용할 수 있습니다.

import UserProfile from '@/components/store/UserProfile.vue';

import { useRoute } from 'vue-router';
import { useListStore } from '@/store';
import { computed } from "vue"
import { UserInfo } from '@/types';

const route = useRoute()
const store = useListStore()

const userName: string | string() = route.params.id

const userInfo = computed(()=> store.user as UserInfo)

store.setUser(userName)

오늘은 Vuex와 피니아를 비교해봤는데 사용하면서 피니아가 컴포지션 API 형태로 사용할때 정말 편하다는걸 느꼈습니다. 오래된 React를 개발할 때도 Redux를 구현하고 싶다면, 소스 파일도 많고 흐름을 따라가기가 정말 혼란스럽고 복잡합니다.라고 느꼈는데 피니아의 경우 별도의 API나 용어를 사용하지 않고 Composition API로 구현되어 일반 props와 state를 관리하듯이 사용하기 매우 편리합니다.나는 그것을 느꼈다.

새로운 Vue3 Composition API를 사용하여 프로젝트를 진행하고 있다면 잘 알려진 Vuex 대신 pinia를 도입하는 것을 고려할 수 있습니다. 오늘 많은 도움이 되셨기를 바라며 다음 포스팅에서 뵙겠습니다. 감사합니다