NodeJS

[NodeJS/VueJS] Vuex 설치 및 사용 #2 - 심화편

Question영 2019. 11. 4. 14:06
반응형

안녕하세요

 

지난번 포스팅때는 Vuex 에 대한 기본적인 설명과 구성 요소, 사용하는 방법에 대해 살펴보았습니다.

 

이번 포스팅에서는 mapGetters, mapMutations, mapActions 에 대해서 살펴보도록하겠습니다.

 

 

시스템 환경

 

 

사용 방법

이름에서 추론해보도록 할까요?

 

지난번 다뤘던 Getter, Mutation, Action 에 앞에 map 이 추가되어 있고 전부 복수형입니다.

 

복수의 기능을 다루기 위한 구조인것을 유추할수 있는데요.

 

정말 맞는지 살펴보도록 하겠습니다.

 

지난번에 사용했던 예제 코드를 다시 한번 보시죠.

 

# HelloWorld.vue

<template>
  <div class="hello">
    Parent counter : {{ getCounter }} <br>
    <button @click="addCounter">+</button>
    <button @click="subCounter">-</button>
    <button @click="doubleCounter">*</button>
    <button @click="asyncAddCounter">~+</button>

    <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props 로 전달한다. -->
    <!-- <child v-bind:passedCounter="counter"></child> -->
    <child></child>
  </div>
</template>

<script>
import Child from './Child.vue'
import {mapGetters, mapMutations, mapActions} from 'vuex'

export default {
  computed: {
    ...mapGetters([
      'getCounter'
    ])
  },
  methods: {
    // 이벤트 추가
    addCounter () {
      let currentCounter = this.$store.commit('addCounter')
      console.log('currentCounter', currentCounter)
    },
    subCounter () {
      // this.$store.state.counter--
      this.$store.dispatch('subCounter')
    },
    ...mapMutations([
      'doubleCounter'
    ]),
    ...mapActions([
      'asyncAddCounter'
    ])
  },
  components: {
    // Child 컴포넌트를 하위 컴포넌트로 등록
    'child': Child
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

 

먼저 vuex 의 기능중 mapGetters, mapMutations, mapActions 기능을 사용을 위한 import 를 해줘야 합니다.

 

import {mapGetters, mapMutations, mapActions} from 'vuex'

 

이 선언은 각 기능을 사용하기 위한 연결이므로 사용하는 기능만 import 하여 사용 가능합니다.

 

import {mapGetters} from 'vuex'

 

요소 중 mapGetters 만 사용하는 경우는 위와 같이 사용합니다.

 

import {mapGetters, mapMutations} from 'vuex'

 

요소 중 mapGetters, mapMutations 만 사용하는 경우는 위와 같이 import 해주면 되는 것이죠.

 

선언을 했으니 사용을 해야죠?

 

mapGetters 를 사용하는 방법은 두가지 입니다.

 

// 네임스페이스 지정 방법 #1
export default {
  computed: mapGetters({
    counter: 'getCounter'
  })
}

// 네임스페이스 생략 방법 #2
export default {
  computed: mapGetters({
    'getCounter'
  })
}

 

첫번째 방법은 조회 기능이 하나뿐일 경우 사용할수 있는 방법입니다.

 

위의 예제에서 몇가지 주의해서 봐야할 사항은 다음과 같습니다.

 

  • vue 의 컴포넌트 생명주기인 computed 에 mapGetters 를 연결
  • mapGetters 기능 연결시 ({}) 구조로 객체를 초기화
  • namespace 의 존재 유/무 (필요시 생략 가능)

예제에서 computed 에 연결한건 값이 변경되었을때 화면상에 자동으로 갱신을 해주기 위해서 입니다.

 

// namespace 가 존재할 경우

<template>
  <div class="hello">
    Parent counter : {{ counter }} <br>
    ...
  </div>
</template>

그리고 counter 처럼 namespace 가 지정되어 있을 경우 템플릿상의 html 태그 기능에서는 위와 같이 활용하면 됩니다.

// namespace 가 존재하지 않을 경우

<template>
  <div class="hello">
    Parent counter : {{ getCounter }} <br>
    ...
  </div>
</template>

 

namespace 는 생략이 가능하며 생략되었을때는 연결된 함수명을 사용하면 이전 예제와 동일한 결과를 얻을수 있습니다.

 

computed 나 methods 등의 속성에 정의 되어 있는 기능은 하나일수도 있지만 대부분 여러 종류입니다.

 

그리고 공통에서 관리하는 조회 기능일수도 있지만 컴포넌트 자체에서 정의한 조회 기능이 있을수도 있습니다.

 

이럴 경우 위의 mapGetters 예제와 다른 방법으로 정의하여 사용해야 합니다.

 

<script>
import {mapGetters} from 'vuex'

export default {
  computed: {
    ...mapGetters([
      'getCounter'
    ]),
    getOnePlusCounter: function () {
      return this.getCounter + 1
    }
  },
  ...
}
</script>

 

다음 예제 코드를 보시면 이전에 mapGetters 예제와 다른 구조인것을 알수 있습니다.

 

  • computed 속성에 mapGetters 를 바로 정의하지 않고 객체로 정의
  • mapGetters 앞에 ... 문구가 추가
  • mapGetters 기능 연결시 ([]) 구조로 객체를 초기화

3가지 사항을 적용시켜주시면 속서어에서 mapGetters 외에 기능 정의가 가능합니다.

 

이 사항은 예로들었던 computed 속성 뿐만 아니라 methods 에서도 동일하게 적용됩니다.

 

<script>
import {mapGetters, mapMutations, mapActions} from 'vuex'

export default {
  ...
  methods: {
    ...
    ...mapMutations([
      'doubleCounter'
    ]),
    ...mapActions([
      'asyncAddCounter'
    ])
  },
  ...
}
</script>

 

이제까지 들었던 mapGetters 적용 방법은 mapMutations, mapActions 에 동일하게 적용되기 때문에

 

별도의 중복된 설명은 하지 않겠습니다.

 

예제에서 methods 에 mapMutations, mapActions 이 두가지를 넣어 놓은 것은

 

엑션 이벤트(여기에서는 클릭 이벤트) 와 연결하기 위한 것입니다.

 

인자 값(Payload) 의 전달

mapMutations, mapActions 로 공통 상태값 수정을 위한 인자 값을 전달할 수 있습니다.

 

# store/index.js

/* eslint-disable eol-last */
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
  ...
  mutations: { // 상태 값을 변경하는 로직을 관리
    addCounter: function (state, payload) {
      console.log(payload)
      state.counter++
    },
    ...
  },
  actions: { // 비동기 통신 및 동작을 정의하고 관리
    ...
    asyncAddCounter: function (context, palyload) {
      return setTimeout(() => {
        context.commit('addCounter')
      }, 1000)
    }
  }
})

 

정의한 store 에 다음과 같이 Mutation 과 Action 이 설정되어 있고

 

이전 예제의 컴포넌트 처럼 mapMutations, mapActions 이 설정되어 있다면

 

탬플릿안의 이벤트 템플릿 속성에서 연결할 공통 상태값 수정 함수를 지정할때 인자 설정하여 전달하면 됩니다.

 

<template>
  <div class="hello">
    Parent counter : {{ getCounter }} <br>
    <button @click="addCounter(10)">+</button>
    ...
    <button @click="asyncAddCounter(20)">~+</button>

    <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props 로 전달한다. -->
    <!-- <child v-bind:passedCounter="counter"></child> -->
    <child></child>
  </div>
</template>

 

위의 예제 처럼 addCounter 와 asyncAddCounter 라는 공통 상태값 수정 함수에

 

각각 10 과 20의 값을 전달하는 것을 보실수 있습니다.

 

<button @click="addCounter({name:'카운트 추가', value: 10})">+</button>

 

여러 인자를 넘기기 위해서는 객체형태로 데이터를 입력하여 전달해줘야 합니다.

 

 

기타 고려 사항들

vuex 에는 포스팅에서 설명하지 않은 여러가지 유용한 기능들이 있습니다.

 

모듈이 대표적인 예인데 이부분도 내용을 정리하려고 했으나

 

특별하게 풀어서 설명할 부분이 많이 없어 (혼동될 여지가 없어서 ...) 포스팅에 자세히 다루지 않았습니다.

 

vuex 에서 사용되는 이름들을 상수(Constant, Type) 로 관리하는 부분도 고려해야 할 사항이나

 

이 부분도 생략하고 넘어간 사항입니다.

 

다른 내용은 vuex 홈페이지나 여러 다른 블로그를 참고하시면 될 것 같네요.

 

수정이나 개선 사항이 있으면 언제든지 덧글 남겨주시면 감사하겠습니다.

 

감사합니다.

반응형