ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [VueJS] Vue의 새로운 상태 관리 : Pinia (피니아 간단 사용법)
    frontend/vue&nuxt 2022. 3. 17. 17:20

    오늘은 Vue3에서 추천하는 상태관리 라이브러리인 Pinia에 대해서 얘기해볼까 합니다. 이때까지 Vue의 상태관리하면 당연하게도 Vuex를 떠올리곤 했는데 작년에 컨퍼런스에서 류에반씨가 직접 Pinia를 추천했었습니다. 메인테이너가 직접 추천하는 상태관리 툴은 알고 있으면 좋을 거라고 생각하며 글을 써봅니다.

     

    우선 Pinia를 쓰기전에 그럼 Vuex는 이제 끝인가요? 라고 물으신다면 그건 또 아닙니다. Vuex의 다음버전인 Vuex5와 Pinia사이의 전환이 매우 쉬울 것이라고 말했으니 그냥 피니아라는 선택지가 하나정도 더 늘었다고 생각하면 될 것 같습니다. React처럼 이제 Redux, Mobx, Recoil 골라 잡듯이.. 이제 Vue도 상태관리 고르는 재미...?가 있을 것 같습니다.

     

    1. Pinia 기본 구조

    1-1. Optional

    // stores/list.js
    import { defineStore } from "pinia";
    
    export const useListStore = defineStore("list",{
      state : () => ({ list: [] }),
      actions: {
        addList(param){
          this.list.push(param);
        }
        //addList: (param) => this.list.push(param);
      },
      getters: {
        getAllList(state){
          return state.list;
        }
        //getAllList: (state) => state.list
      }
    });

    1-2. Composition

    // stores/list.js
    import { defineStore } from "pinia";
    import { ref, computed } from "vue";
    
    export const useListStore = defineStore("list", () => {
      const list = ref([]);
      function addList(param) {
        list.value.push(param);
      }
      const getDataAll = computed(() => list.value);
      return { list, addList, getDataAll };
    });

    Pinia는 기본적으로 위와 같이 state, actions, getters의 구조로 되어 있습니다. mutations이 없어지고 action에서 처리되게 바뀌었습니다. 또한 Pinia는 Vue3 Composition API에 익숙한 개발자를 위한 코드 작성 방식을 제공하고 있습니다.

     

    이렇게 작성된 코드를 Vue 컴포넌트 내에서는 어떻게 사용하는지 살펴 보도록 하겠습니다.

     

    2. Vue

    2-1. Optional

    <template>
      <div>
        <input type="text" v-model="text" />
        <button @click="onClickAddList">추가</button>
        <h4>추가된 목록</h4>
        <p v-for="(item, index) in getDataAll" :key="index">
          {{ item }}
        </p>
      </div>
    </template>
    <script>
    import { mapActions, mapState } from "pinia";
    import { useListStore } from "./stores/list";
    export default {
      data: () => ({
        text: "",
      }),
      computed: {
        ...mapState(useListStore, ["getDataAll"]),
      },
      methods: {
        ...mapActions(useListStore, ["addList"]),
        onClickAddList() {
          if (!this.text) return;
          this.addList(this.text);
          this.text = "";
        },
      },
    };
    </script>

    2-2. Composition

    <template>
      <div>
        <input type="text" v-model="text" />
        <button @click="addList(text)">추가</button>
        <h4>추가된 목록</h4>
        <p v-for="(item, index) in getDataAll" :key="index">
          {{ item }}
        </p>
      </div>
    </template>
    <script>
    import { computed, ref } from "vue";
    import { useListStore } from "./stores/list";
    //구조분해할당 활용
    //import { storeToRefs } from "pinia";
    
    export default {
      setup() {
        const text = ref("");
        const list = useListStore();
        //구조분해할당 활용
        //const { getDataAll } = storeToRefs(list);
        
        function addList() {
          if (!text.value) return;
          list.addList(text.value);
          //액션 후촐 외에도 직접 내부 API로 데이터 변경 가능.
          //list.$patch({ list: [...list.getDataAll, text.value] });
          text.value = "";
        }
    
        return {
          text,
          addList,
          getDataAll: computed(() => list.getDataAll),
          //구조분해할당 활용
          //getDataAll
        };
      },
    };
    </script>

    Vue 컴포넌트 내에서는 위와 같은 형식으로 사용할 수 있습니다. useListStore를 import해주고 내부의 코드를 호출해서 동작시키면 됩니다. 내부의 state를 변경 시키기위해 action을 사용할 수도 있지만, 이 외에도 내부 API인 $patch를 통해서 변경시킬 수 있습니다. 또한, computed 대신 구조분해 할당을 활용하게 되면 Vue3에서 반응형이 깨지기 떄문에 storeToRef로 묶어서 반응형으로 유지시켜 줍니다.

     

    실제로 사용해봤을 때는 Composition API 스타일로 작업할 때 조금 더 잘어울리는 느낌을 받을 수 있었습니다. mutations등을 작성하지 않아도 되서 작업량이 많이 줄은 느낌을 받을 수 있습니다. 실제로 현재 하고있는 nextjs 사이드 프로젝트가 끝나면 vue+pinia로 사이드 프로젝트 하나 해보면 더 장단점을 알 수 있을 것 같습니다. 타입스크립트도 지원하고 devtools도 공식지원하니 좋은 선택지가 하나 더 생긴 기분입니다. 다음에 좀 더 깊게 판 후에 설명드리겠습니다.

     

    샘플 코드 보러 가기

    반응형

    댓글

Designed by Tistory.