2018-09-18 Vue 상태관리(Vuex) - 모듈

Vue 상태관리(Vuex) - 모듈(Module)

모듈(Module)?

- Vuex 가 다루는 상태, 액션, 변이 메서드의 수가 증가하면, 개라밪가 유지보수 하기 어려움.
- 애플리케이션 규모가 커짐에 따라, 저장소를 분리할 필요가 있음.

-> 위와 같은 목적으로 사용할 수 있도록 Vuex 에서 모듈 개념을 지원. 모듈은 분리된 저장소를 하나의 저장소 객체인
것처럼 다룰 수 있도록 도와줌.

Vuex Module


Vuex.Store 클래스의 modules 옵션에 지역 저장소 객체를 제공.

modules 옵션을 이용.
객체옵션.
예시)
  modules: {
    <모듈이름> : <지역 저장소 객체>,  
  }

지역 저장소 객체는
state
mutations
actions
getters
modules
위와 같은 옵션을 사용할 수 있다.


module 을 생성해주자.
src/stoer_modules/

moduleA.js
moduleB.js
생성

export const moduleA = {
  state: {
    aNum: 100
  },
  mutations: {
    increment: (state) => {
      state.aNum++
    },
    getters: {
      getNum: (state) => {
        return state.aNum
      }
    }
  }
}

export const moduleB = {
  state: {
    bNum: 999
  },
  mutations: {
    increment2: (state) => {
      state.bNum++
    },
    getters: {
      getNum2: (state) => {
        return state.bNum
      }
    }
  }
}


store.js

import Vue from 'vue'
import Vuex from 'vuex'
import {moduleA} from './store_modules/moduleA'
import {moduleB} from './store_modules/moduleB'

Vue.use(Vuex)

export default new Vuex.Store({
  // modules 추가
  modules: {
    a: moduleA,
    b: moduleB
  },
  // countNum 을 state 속성 추가
  state: {
    countNum: 0
  },
  getters: {
    getCountNumFromStore: (state) => {
      return state.countNum
    }
  },
  mutations: {
    addCountNum: function (state) {
      state.countNum++
    },
    addCountNum2: function (state, payload) {
      state.countNum += payload.num
    },
    subtractionCountNum: function (state) {
      state.countNum--
    }
  },
  actions: {
    addCount: function (context) {
      // commit 의 대상인 addCountNum 는 mutations 의 메서드를 의미한다.
      return context.commit('addCountNum')
    },
    decreaseCount: function (context) {
      // Promise 객체를 명시적으로 반환하는 액션 메서드
      return new Promise((resolve, reject) => {
        resolve()
        setTimeout(function () {
          context.commit('subtractionCountNum')
        }, 1000)
      })
    }
  }
})


componetns 에서 접근을 해보자.

this.$store.getters.getNum
this.$store.commit('increment')

this.$store.getters.getNum2
this.$store.commit('increment2')

위와 같이 사용하면, 접근이 가능하다.

* 선언한 상태, 변이 메서드는 store 객체에서 처음부터 하나의 저장소 객체로 선언된 것처럼 사용할 수 있다.


Vuex Module 속성 이름 관리

- 모듈을 사용해, 저장소를 구성하면 설장한 속성 이름이 모두 달라야함.
- Vuex 가 지역저장소 모든 속성을 Vuex의 전역으로 등록하기 때문.
- 이를 위해, 이름을 접두사 / 접미사를 포함해 상수로 정의하는 것을 권장



namespace 같이 옵션을 주는 방식도 있는데, 일단 패스.


export const types = {
  getters: {
    GET_STATE_C_NUM: 'GET_STATE_C_NUM'
  }
}


import {types} from './types/modueCTypes' // types 선언
const GET_C_NUM = 'c/GET_C_NUM'
const INCREMENT_C_NUM = 'c/C_INCREMENT'

const moduleC = {
  state: {
    todos: [{cNum: 10000}]
  },
  mutations: {
    [INCREMENT_C_NUM]: function (state) {
      state.todos[0].cNum += 100
    }
  },
  getters: {
    [GET_C_NUM]: function (state) {
      // getters['c/GET_C_NUM']
      return state.todos[0].cNum
    },
    [types.getters.GET_STATE_C_NUM]: (state) => {
      return state.todos[0].cNum
    }
  }
}

export default moduleC

나는 위와 같은 방식으로 이용하였다. 사용할 때는
import { mapGetters, mapMutations, mapActions, mapState } from 'vuex'
Vuex 에 내장된 helper 함수를 사용했다.


mapGetters({
  parentCounter : 'getCounter' // getCounter 는 Vuex 의 getters 에 선언된 속성 이름
})


mapGetters([
 'getCounter'
])

위의 헬퍼 함수를 사용할 때, ES6의 ... (전개) 연산자를 사용한다.

computed 속성 - {}
mapGetters
mapState

methods 속성 - {}
mapMutations
mapActions

------

<template>
  <div>
    <p><router-link to="/">Go to First Page</router-link></p>
    <p>moduleA : </p>
    <p>moduleB : </p>
    <p>moduleC : </p>
    <p>moduleC(types 로 속성값을 관리하는 방식) : </p>
    <button @click="incrementNumA">+ 증가(a 모듈)</button>
    <button @click="incrementNumB">+ 증가(b 모듈)</button>
    <button @click="incrementNumC">+ 증가(C 모듈)</button>
    <hr>
    <ul>
      <li v-for="(item, index) in todos" v-if="item.done" :key="item.text" @click="toggleTest(index)"></li>
    </ul>
  </div>
</template>

<script>
import { mapGetters, mapMutations, mapActions, mapState } from 'vuex'
import {types} from '../../store_modules/types/modueCTypes'

export default {
  name: 'vuexModule',
  computed: {
    ...mapGetters(['todos/DONE_COUNT']),
    ...mapState({
      todos: (state) => state.todo.todos
    }),
    ...mapGetters({getNum: 'getNum', getNum2: 'getNum2', getCNum: 'c/GET_C_NUM', test: types.getters.GET_STATE_C_NUM})
  },
  methods: {
    ...mapMutations({incrementC: 'c/C_INCREMENT'}),
    ...mapActions({fetchTest: 'todos/FETCH_ALL'}),
    incrementNumA () {
      console.log(this.$store)
      this.$store.commit('increment')
    },
    incrementNumB () {
      this.$store.commit('increment2')
    },
    incrementNumC () {
      this.incrementC()
    },
    toggleTest (index) {
      console.log(index)
      this.fetchTest({index: index, done: false})
    }
  }
}
</script>

<style scoped>

</style>

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import {moduleA} from './store_modules/moduleA'
import {moduleB} from './store_modules/moduleB'
import moduleC from './store_modules/moduleC'
import todosModule from './store_modules/todosModule'

Vue.use(Vuex)

export default new Vuex.Store({
  // modules 추가
  modules: {
    a: moduleA,
    b: moduleB,
    c: moduleC,
    todo: todosModule
  },
  // countNum 을 state 속성 추가
  state: {
    countNum: 0
  },
  getters: {
    getCountNumFromStore: (state) => {
      return state.countNum
    }
  },
  mutations: {
    addCountNum: function (state) {
      state.countNum++
    },
    addCountNum2: function (state, payload) {
      state.countNum += payload.num
    },
    subtractionCountNum: function (state) {
      state.countNum--
    }
  },
  actions: {
    addCount: function (context) {
      // commit 의 대상인 addCountNum 는 mutations 의 메서드를 의미한다.
      return context.commit('addCountNum')
    },
    decreaseCount: function (context) {
      // Promise 객체를 명시적으로 반환하는 액션 메서드
      return new Promise((resolve, reject) => {
        resolve()
        setTimeout(function () {
          context.commit('subtractionCountNum')
        }, 1000)
      })
    }
  }
})


Categories:

Updated:

Comments