HEROPY
Tech
{{ scrollPercentage }}%

Vuex - 6 - Helpers(Mapping)

js vue vuex

기존에 작성한 코드를 조금 수정해서 Vuex Helpers를 사용해 보겠습니다.
Helpers는 컴포넌트의 computedmethods 속성에 Vuex 저장소(Store) 내용을 바인딩하여 좀 더 직관적으로 사용할 수 있게 도와줍니다.

Vuex에서 사용하는 상태(State), 게터(Getters), 변이(Mutations), 액션(Actions)을 맵핑할 수 있습니다.

  • mapState
  • mapGetters
  • mapMutations
  • mapActions

먼저, FruitsList.vue를 수정하겠습니다.

<!--FruitsList.vue-->
<!-- ... -->

<script>
  import { mapState, mapGetters } from 'vuex';

  export default {
    computed: {
      ...mapState([  // ES6 - Spread
        'fruits'
      ]),
      ...mapGetters([  // ES6 - Spread
        'upperCaseFruits'
      ])
    }
  }
</script>

<style></style>

상태(State)를 바인딩하기 위해서 mapState를 사용했고,
게터(Getters)를 위해 mapGetters를 사용했습니다.

문법적으로 객체의 속성이나 메소드 자리에서는 함수 실행을 할 수 없는데, 함수 앞에 전개 연산자(Spread / ...)를 사용하면 객체의 일부로 확장해서 사용할 수 있습니다.
Helpers는 이 방식을 사용하여 작성합니다.

우선 문제가 없는지 결과를 확인하세요.
혹시 전개 연산자 때문에 문제가 있다면 ‘Babel Preset’이 필요할 수 있습니다.

$ npm install --save-dev babel-preset-es2015
// .babelrc
{
  "presets": ["es2015"]
}

잘 나오는지 확인하셨다면 다음 컴포넌트들도 수정하겠습니다.

<!--FruitsPrice.vue-->
<!-- ... -->

<script>
  import { mapState } from 'vuex';

  export default {
    computed: {
      ...mapState(['fruits'])
    }
  }
</script>

<style></style>

BtnDiscount.vue의 경우 mapActions를 사용합니다.

기존 코드에서는 dispatch 메소드에 Payload 인자로 할인율을 전달해서 사용했습니다.

discountPrice() {
  this.$store.dispatch('discountPrice', {
    discountRate: 20
  });
}

하지만 mapActions로 맵핑하면 Payload 인자를 직접 사용할 수 없기 때문에, 별도 데이터를 만들어서 클릭 이벤트가 발생할 때 인자로 사용합니다.

<!--BtnDiscount.vue-->
<template>
  <div class="btn" @click="discountPrice(discountData)">DISCOUNT PRICE</div>
</template>

<script>
  import { mapActions } from 'vuex';

  export default {
    data() {
      return {
        discountData: {
          rate: 20
        }
      }
    },
    methods: {
      ...mapActions([
        'discountPrice'
      ])
    }
  }
</script>

<!-- ... -->

이벤트 발생의 전달 인자로 discountData라는 객체를 만듭니다.
discountData 객체는 rate 속성을 가지는데 저장소(Store)에는 Payload가 discountRate 속성을 사용하도록 작성되어 있습니다.
이름을 수정하겠습니다.

// store.js
// ...

export const store = new Vuex.Store({
  state: {
    // ...
  },
  getters: {
    // ...
  },
  mutations: {
    discountPrice(state, payload) {
      state.fruits.forEach(fruit => {
        fruit.price *= (100 - payload.rate) / 100;  // discountRate >> rate
      });
    }
  },
  actions: {
    // ...
  }
});

Helpers를 사용해서 모두 수정했습니다.
잘 동작하는지 확인하세요.

혹시 매핑한 이름이 최적화가 아니거나 적당하지 않다면, 다음과 같이 컴포넌트 안에서 맵핑하는 메소드의 이름을 변경해 사용할 수 있습니다.

<!--BtnDiscount.vue-->
<template>
  <div class="btn" @click="price(discountData)">DISCOUNT PRICE</div>
</template>

<script>
  import { mapActions } from 'vuex';

  export default {
    data() {
      return {
        discountData: {
          rate: 20
        }
      }
    },
    methods: {
      ...mapActions({
        price: 'discountPrice'
      })
    }
  }
</script>

<!-- ... -->