ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Vue.js] Vuex - (3) Store 모듈화
    Front-End(Web)/Vue 2021. 6. 13. 23:51
    반응형

    이전에 진행한 프로젝트는 Vuex Store에 state, getter, mutations 들이 일괄적으로 들어가는 형태였다.

    아무래도 프로젝트의 규모가 커지면, 당연히 Store 자체의 코드량도 많아지고 유지보수도 힘들어질 것이다.

     

    이러한 부분을 ES6 import/export 문법을 통해 좀 더 용이하게 분리하는 모듈화에 대해 간단하게 정리해보았다.

    (개념보다는 Vuex의 코딩기법의 내용이기에 분량이 많지 않다.)

     

    * 이 글은 캡틴판교님의 Vue.js 강의 및 블로그를 기반으로 학습한 내용을 정리하고 있습니다.


    💚 Getters, Mutations 분리

    공식문서에서는, Vue.js 애플리케이션의 복잡한 컴포넌트들을 관리하는 상태관리 패턴 + 라이브러리로 정의한다.

    컴포넌트들에 대한 중앙 집중식 저장소 역할을 하며, 예측 가능한 방식으로 상태를 변경할 수 있다.

     

    먼저, Store에 getters, mutations JS파일을 만들어준다. 각각의 파일에 우리가 작성한 getters, mutations가 들어간다.

     

    // mutations.js
    
    const addTodo = (state, text) => {
      if (!text) {
        state.isModalOn = true;
      }
      else {
        const newItem = {
          text,
          done: false,
        }
        state.todoList.push(newItem);
      }
    }
    
    const toggleDoneTodo = (s, idx) => {
      s.todoList[idx].done = !s.todoList[idx].done;
    }
    
    const removeTodo = (s, idx) => {
      s.todoList.splice(idx, 1);
    }
    
    const clearTodos = (s) => {
      s.todoList = [];
    }
    
    const saveTodos = (s) => {
      sessionStorage.setItem('todos', JSON.stringify(s.todoList));
    }
    
    const toggleModal = (state, bool) => {
      state.isModalOn = bool;
    }
    
    export { addTodo, toggleDoneTodo, removeTodo, clearTodos, saveTodos, toggleModal };

    mutations.js 에서 각각의 함수들을 Arrow Function 표현식으로 선언한 뒤, 이 모듈을 외부에서 사용할 수 있도록 export 한다.

     

    // store.js
    import Vue from 'vue'
    import Vuex from 'vuex'
    import * as mutations from './mutations';		// 1) mutations 메서드들을 import
    
    Vue.use(Vuex)
    
    const savedTodos = sessionStorage.getItem('todos');
    
    export const store = new Vuex.Store({
      state: {
        headerText: "To-Do List!!!",
        todoList: savedTodos ? JSON.parse(savedTodos) : [],
        isModalOn: false,
      },
      mutations,						// 2) mutations 를 store 내장
    });

    store.js 에서는 먼저, mutations의 모든 메서드를 import * as [변수명] from '경로' 문법을 통해 가져온다.

    이를, Store에 내장해주기만 하면 된다. mutations 변수명에 담아 가져왔기 때문에, Store의 mutations 필드에 등록될 수 있다.

    * getters, actions 도 위 패턴처럼 적용할 수 있다.

     

    💚 Store 모듈화

    상대적으로 규모가 작다면, Store의 각 필드를 위처럼 분리할 수 있다. 하지만 규모가 커질수록 사용되는 상태나 메서드들도 많아질 것이다.

    그렇기에, 이런 기능적인 분리보다 서로 연관있는 필드들끼리 병합하는 모듈화의 방법이 권장되었다.

     

    이처럼, Store 디렉토리에 modules 디렉토리를 새로 생성한다. 여기에, Todo 기능을 모듈화할 TodoModule.js 파일을 만들었다.

     

    // store.js
    
    import Vue from 'vue'
    import Vuex from 'vuex'
    import TodoModule from './modules/TodoModule'
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({
      modules: {
        TodoModule,
      },
    });

    store.js 를 먼저 보면, 모듈화할 TodoModule 을 import 한 뒤 Store의 modules 필드를 새로 만들어 여기에 넣어주기만 하면 된다.

     

    // TodoModule.js
    
    const savedTodos = sessionStorage.getItem('todos');
    
    const state = {
      headerText: "To-Do List!!!",
      todoList: savedTodos ? JSON.parse(savedTodos) : [],
      isModalOn: false,
    }
    
    const getters = {
      // no getters
    }
    
    const mutations = {
      addTodo(state, text) {
        if (!text) {
          state.isModalOn = true;
        }
        else {
          const newItem = {
            text,
            done: false,
          }
          state.todoList.push(newItem);
        }
      },
      toggleDoneTodo(s, idx) {
        s.todoList[idx].done = !s.todoList[idx].done;
      },
      removeTodo(s, idx) {
        s.todoList.splice(idx, 1);
      },
      clearTodos(s) {
        s.todoList = [];
      },
      saveTodos(s) {
        sessionStorage.setItem('todos', JSON.stringify(s.todoList));
      },
      toggleModal(state, bool) {
        state.isModalOn = bool;
      },
    }
    
    export default { 
      state,
      getters,
      mutations,
    }

    TodoModule.js 모듈 파일에선, 각각의 state, getter, mutations 변수에 기존 Store 방식처럼 객체형태로 값이나 메서드를 담는다.

    이를, export default를 통해 모듈을 내보내며, state, getters, mutations 각각의 필드를 갖는 객체형태로 내보낸다.

     

    - 지역 모듈 매개변수

    독립된 모듈 파일을 지역 모듈이라고 칭한다. 여기의 getters, 메서드들은 본인의 상태뿐만 아니라, 상위의 상태도 참조할 수 있다.

    const moduleA = {
      // ...
      getters: {
        sumWithRootCount (state, getters, rootState) {
          return state.count + rootState.count
        }
      }
      actions: {
        incrementIfOddOnRootSum ({ state, commit, rootState }) {
          if ((state.count + rootState.count) % 2 === 1) {
            commit('increment')
          }
        }
      }
    }

    이처럼, 1, 2번째 인자는 해당 지역모듈의 state, getters(혹은 메서드) 가 된다.

    그리고, 세 번째 인자는 모듈이 사용되는 상위(통상 Store)의 상태값을 참조할 수 있다.


    💚 어플리케이션 구조

    Vuex 공식문서에 소개된 내용으로, 코드구조가 정해져있진 않으나 아래 원칙을 권장한다.

     

    1. 어플리케이션 레벨의 상태는 중앙 집중되기 위해 Store에서 관리한다.
    2. 상태를 변경시키는 유일한 방법은, mutations를 commit 하는 것이다. (Flux 패턴)
    3. 비동기 로직은 캡슐화되어야하며 이는 actions로 구성된다.
    ├── index.html
    ├── main.js
    ├── api
    │   └── ... # API 요청을 위한 추상화를 포함합니다.
    ├── components
    │   ├── App.vue
    │   └── ...
    └── store
        ├── index.js          # 모듈을 조합하고 저장소를 내보내는 곳 입니다.
        ├── actions.js        # 루트 액션
        ├── mutations.js      # 루트 변이
        └── modules
            ├── cart.js       # cart 모듈
            └── products.js   # products 모듈

    Vue 프로젝트 규모가 커질때, Vuex Store의 구조화 및 분리를 하는 방법에 대한 학습 및 고찰이었다.

    프로젝트의 규모에 따라 다르겠지만, 실제 웹 어플리케이션을 구현하면 모듈화의 방법이 좀 더 어울릴 것 같다.

    이 때, 관련성 있는 기능들끼리(인증/인가, 모달창 등) 모듈을 나눠 각각에서 상태 및 메서드를 관리하면 확실히 깔끔할 것 같다.

     

    [출처]

    - Vuex 공식문서(번역본) : https://vuex.vuejs.org/kr/guide/structure.html

    - Vuex 캡틴판교 님의 블로그 : https://joshua1988.github.io/web-development/vuejs/vuex-actions-modules/

    반응형

    'Front-End(Web) > Vue' 카테고리의 다른 글

    [Vue.js] Transition & Animation  (0) 2021.07.14
    [Vue.js] 컴포넌트 톺아보기  (0) 2021.06.14
    [Vue.js] Vuex - (2) Helper 함수  (0) 2021.06.11
    [Vue.js] Vuex - (1) Vuex 기본  (0) 2021.06.10
    [Vue.js] Template 문법  (0) 2021.06.03
Designed by Tistory.