front-end/Vue.js

Vuex 기초배우기 #4 (mapState, mapGetters)

정구 2022. 2. 22. 10:23
728x90
mapState와 mapGetters는 state, getters를 보다 쉽게 사용할 수 있게 도와준다

 

 

 

앞의 코드에서 좀 더 복잡한 계산을 getters에 작성해보겠다.

전체 유저에서 서울에 살고 있는 사람의 수와 그 퍼센트를 계산해준다.

 

 

src/store.js

getters: {
    allUsersCount: (state) => {
      return state.allUsers.length;
    },
    countOfSeoul: (state) => {
      let count = 0;
      state.allUsers.forEach((user) => {
        if (user.address === "Seoul") count++;
      });
      return count;
    },
    percentOfSeoul: (state, getters) => {
      return Math.round((getters.countOfSeoul / getters.allUsersCount) * 100);
    },
  },
percentOfSeoul에서 getters만 인자로 받으면 될 것 같지만
countOfSeoul과 allUsersCount의 값은 state를 인자로 받아 만들어졌기 때문에
state도 꼭 인자로 넣어준다.

 

 

state를 인자로 받지 않았을 경우 제대로 계산하지 못한다.

 

 

state, getters 둘다 인자로 받은경우 제대로 계산이 된다

 

 

 

countOfSeoul과 percentOfSeoul을 컴포넌트에서 사용해준다.

 

 

src/components/Users/AllUsers.vue

<template>
  <div>
    <h1>All Users({{ $store.getters.allUsersCount }})</h1>
    <h3>
      Seoul Users: {{ $store.getters.countOfSeoul }}({{$store.getters.percentOfSeoul}}%)
    </h3>
    <v-list two-line>
      <v-list-tile
        v-for="(user, index) in $store.state.allUsers"
        :key="index"
        avatar
      >
        <v-list-tile-avatar color="grey lighten-3">
          <img :src="user.src" />
        </v-list-tile-avatar>

        <v-list-tile-content>
          <v-list-tile-title v-html="user.name"></v-list-tile-title>
          <v-list-tile-sub-title
            >id:#{{ index }} / {{ user.address }} 거주</v-list-tile-sub-title
          >
        </v-list-tile-content>
      </v-list-tile>
    </v-list>
  </div>
</template>

 

 

$store.getters에 계속 접근해야 하는, 반복적인 코드를 사용해야 하는 불편함이 생긴다.

 

이때 사용할 수 있는 것이 바로 mapGetters이다.

 

 

 

vuex에서 제공하는 기능으로 컴포넌트에서 getters에 바로 접근할 수 있게 만들어준다.

 

 

src/components/Users/AllUsers.vue

<template>
  <div>
    <h1>All Users({{ allUsersCount }})</h1>
    <h3>Seoul Users: {{ countOfSeoul }}({{ percentOfSeoul }}%)</h3>
    <v-list two-line>
      <v-list-tile
        v-for="(user, index) in $store.state.allUsers"
        :key="index"
        avatar
      >
        <v-list-tile-avatar color="grey lighten-3">
          <img :src="user.src" />
        </v-list-tile-avatar>

        <v-list-tile-content>
          <v-list-tile-title v-html="user.name"></v-list-tile-title>
          <v-list-tile-sub-title
            >id:#{{ index }} / {{ user.address }} 거주</v-list-tile-sub-title
          >
        </v-list-tile-content>
      </v-list-tile>
    </v-list>
  </div>
</template>

<script>
import { EventBus } from "@/main.js";
import { mapGetters } from "vuex";

export default {
  data() {
    return {};
  },
  computed: {
    ...mapGetters(["allUsersCount", "countOfSeoul", "percentOfSeoul"]),
  },
  mounted() {
    EventBus.$on("signUp", (users) => {
      this.$store.state.allUsers.push(users);
    });
  },
};
</script>
mapGetters를 객체로 import해주고 (이때 vuex에서 제공해주는 기능이기에 from 'vuex'로 적어야 한다.
computed에... mapGetters( [ ' ' ] ) 형식으로 getters에서 가져올 데이터를 선언해준다.
template에서는 $store.getters를 지우고 이름만 가지고 사용할 수 있다.

 

 

 

 

만약 getters에서 가져온 값들을 현재 컴포넌트에서 다른 이름으로 사용하고자 하면 배열이 아닌 객체 형식으로 선언해 주면 된다.

 

computed: {
  ...mapGetters({
    count: 'allUsersCount',
    seouls: 'countOfSeoul',
    percent: 'percentOfSeoul'
  })
}

 

state 또한 mapGetter처럼 mapState를 사용할 수 있다.

 

 

 

src/components/Users/AllUsers.vue

<template>
  <div>
    <h1>All Users({{ count }})</h1>
    <h3>Seoul Users: {{ seouls }}({{ percent }}%)</h3>
    <v-list two-line>
      <v-list-tile v-for="(user, index) in allUsers" :key="index" avatar>
        <v-list-tile-avatar color="grey lighten-3">
          <img :src="user.src" />
        </v-list-tile-avatar>

        <v-list-tile-content>
          <v-list-tile-title v-html="user.name"></v-list-tile-title>
          <v-list-tile-sub-title>
            id:#{{ index }} / {{ user.address }} 거주
          </v-list-tile-sub-title>
        </v-list-tile-content>
      </v-list-tile>
    </v-list>
  </div>
</template>

<script>
import { EventBus } from "@/main.js";
import { mapState, mapGetters } from "vuex";

export default {
  data() {
    return {};
  },
  computed: {
    ...mapGetters({
      count: "allUsersCount",
      seouls: "countOfSeoul",
      percent: "percentOfSeoul",
    }),
    ...mapState(["allUsers"]),
  },
  mounted() {
    EventBus.$on("signUp", (users) => {
      this.allUsers.push(users);
    });
  },
};
</script>
mapState와 mapGetters를 통해 정리된 모습
훨씬 가독성이 좋아지고 깔끔해졌다.

 

728x90