[Vue.js] 11 Vuex Helper

2021. 9. 24. 09:58Study/Vue.js

반응형

Vuex Helper

  • Vuex의 각 속성들을 더 쉽게 사용하는 방법 - Helper
  • Store에 있는 아래 4가지 속성들을 간편하게 코딩하는 방법
    • state -> mapState
    • getters -> mapGetters
    • mutations -> mapMutations
    • actions -> mapActions

Helper의 사용법

  • helper를 사용하고자 하는 vue 파일에서 아래와 같이 해당 helper를 로딩
  • 만약 헬퍼를 사용하지 않았다면, State에 정의 된 num에 접근하려면 this.$store.state.num 와 같이 접근해야 한다.
  • 생소하게 보이는 mapState앞에 있는 ...은 ES6의 Object Spread Operator이다.
//App.vue
import { mapState } from 'vuex';
import { mapGetters } from 'vuex';
import { mapMutations } from 'vuex';
import { mapActions } from 'vuex';

export default {
   computed() {
       ...mapState(['num']),
       ...mapGetters(['countedNum'])
  },
   methods: {
       ...mapMutations(['clickBtn']),
       ...mapActions(['asyncClickBtn'])
  }
}

mapState, mapGetters

  • mapState
    • vuex에 선언한 state 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
    • vuex에서 mapState 함수를 가져와서 ... 연산자로 연결하고, 배열리터럴로 확장해서 사용한다.
    • vuex store에 선언된 state에 this.$store.state로 접근하지 않아도 됨
    • 또, vue 템플릿에서 state안에있는 num 접근할 때도 this.num으로 바로 접근 가능하다.
// App.vue
import { mapState } from 'vuex';

computed() {
   ...mapState(['num'])
   // num() { return this.$store.state.num; } 를 대체함
}

// store.js
state: {
   num: 10
}
<!-- <p>{{ this.$store.state.num }}</p> -->
<p>{{ this.num }}</p>
  • mapGetters
    • vuex에 선언한 getters 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
    • vuex store에 선언된 getters에 this.$store.getters로 접근하지 않아도 됨
    • getters는 vuex를 적용하기 전 사용하던 computed 속성이라고 생각하면 된다.
// App.vue
import { mapGetters } from 'vuex';

computed: {
   ...mapGetters(['reverseMessage'])
}

// store.js
getters: {
   reverseMessage(state) {
       return state.msg.split('').reverse().join('');
  }
}
<!-- <p>{{ this.$store.getters.reverseMessage }}</p> -->
{{ this.reverseMessage }}

ES6 Spread 연산자를 쓰는 이유

  • 싱글파일 컴포넌트 구조의 각 컴포넌트에서 정의된 computed 속성이 있을 것이고,
  • 거기에 Vuex store에 정의된 getters를 사용해야하는 상황이 있을 것이다.
  • 이때, ... 연산자를 통해 mapGetters를 연결해줘야 컴포넌트에서 computed 속성과 Vuex의 store에 등록된 getters를 함께 사용할 수 있다.

mapMutations, mapActions

  • mapMutations
    • Vuex에 선언한 mutations 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
      • 컴포넌트에서 버튼 클릭시 컴포넌트의 methods에 clickBtn이 정의 되어있는 것 처럼 동작한다.
      • 하지만 실제로는 ...mapMutations를 통해서 Vuex Store에 등록된 함수를 쓴다.
      • 따라서, Vuex에 정의된 state.msg가 alert로 뜨게 될 것이다.
// App.vue
import { mapMutations } from 'vuex';

methods: {
   ...mapMutations(['clickBtn']),
   authLogin() {},
   displayTable() {}
}

// store.js
mutations: {
   clickBtn(state) {
       alert(state.msg);
  }
}

<button @click="clickBtn">popup message</button>
  • mapActions
    • Vuex에 선언한 actions 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
      • 마찬가지로 컴포넌트에서 버튼 클릭으로 methods에 등록된 delayClickBtn을 호출한다.
      • methods에는 Spread Operator로 store의 actions에 정의된 delayClickBtn을 등록한다.
// App.vue
import { mapActions } from 'vuex';

methods: {
   ...mapActions(['delayClickBtn'])
}

// store.js
actions: {
   delayclickBtn(context) {
       setTimeout(() => context.commit('clickBtn'), 2000);
  }
}

<button @click="delayClickBtn">delay popup message</button>

Helper의 유연한 문법

  • Vuex의 선언한 속성을 그대로 컴포넌트에 연결하는 문법
// 배열 리터럴
...mapMutations([
   'clickBtn',    //'clickBtn': clickBtn
   'addNumber'    //addNumber(인자)
])
  • addNumber(인자)의 경우 배열리터럴로 넘기는 string에 선언을 안해도 알아서 넘겨준다!
  • Vuex에 선언한 속성을 컴포넌트의 특정 메서드에다가 연결하는 문법
// 객체 리터럴
...mapMutations({
   popupMsg: 'clickBtn'    // 컴포넌트 메서드 명 : Store의 Mutation 명
})
  • 컴포넌트에서 사용하는 메서드와 Store의 Mutation 명이 다를 경우 객체 리터럴을 사용해서 등록할 수 있다.

Helper 함수가 주는 간편함

  • demoStore.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.store({
   state: {
       price: 100
  },
   getters: {
       originalPrice(state) {
           return state.price;
      },
       doublePrice(state) {
           return state.price * 2;
      },
       triplePrice(state) {
           return state.price * 3;
      }
  }
})
  • 헬퍼를 사용하지 않고 Vuex를 적용한 컴포넌트 - Demo.vue
<template>
   <div id="root">
       <p>{{ originalPrice }}</p> //100
       <p>{{ doublePrice }}</p>   //200
       <p>{{ triplePrice }}</p>   //300
   </div>
</template>

<script>
 export default {
     computed: {
         originalPrice() {
             return this.$store.getters.originalPrice;
        },
         doublePrice() {
             return this.$store.getters.doublePrice;
        },
         triplePrice() {
             return this.$store.getters.triplePrice;
        },
    },
};
</script>
  • Vuex 의 헬퍼함수를 사용하면 반복 코드를 줄이고 편하게 Vuex store에 접근할 수 있다.
  • template영역에 this.로 스토어에 바로 접근해도 되지만 영역에 표현식을 줄이는 것을 권고한다.
  • 스크립트영역에서 store로 값을 받아온다.
<script>
 import { mapGetters } from 'vuex';

 export default {
     computed: {
         ...mapGetters(['originalPrice', 'doublePrice', 'triplePrice'])
    },
};
</script>

Vuex 프로젝트 구조화 및 모듈화

  • 애플리케이션에 스토어를 적용해서 사용하다가 보면 금방 스토어의 덩어리가 커지므로 데이터(상태)의 성격별로 스토어를 모듈화 해주면 훨씬 관리하기가 수월하다.

방법 1 - 속성별 파일로 구조화

  • store 디렉토리 구조
    • store
      • getters.js
      • mutations.js
      • store.js
* mutations.js

const addOneItem = (state, todoItem) => {
 const obj = {completed: false, item: todoItem};
 sessionStorage.setItem(todoItem, JSON.stringify(obj));
 state.todoItems.push(obj);
}

const removeOneItem = (state, payload) => {
 sessionStorage.removeItem(payload.todoItem.item);
 state.todoItems.splice(payload.index, 1);
}

const toggleOneItem = (state, payload) => {
 state.todoItems[payload.index].completed = !state.todoItems[payload.index].completed;
 sessionStorage.removeItem(payload.todoItem.item);
 sessionStorage.setItem(payload.todoItem.item,
                        JSON.stringify(payload.todoItem));
}

const clearAll = (state) => {
 state.todoItems = [];
 sessionStorage.clear();
}

export { addOneItem, removeOneItem, toggleOneItem, clearAll }
* store.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as getters from './getters';
import * as mutations from './mutations'

Vue.use(Vuex);

export const store = new Vuex.Store({
 state: {
   todoItems: storage.fetch()
},
 getters,
 mutations
})

방법 2 - 앱이 비대해져서 1개의 store로는 관리가 힘들 때 modules 속성 사용

  • 모듈별로 필요한 store 속성들을 모아서 관리한다.
  • store 디렉토리 구조
    • store
      • moduels
        • todoApp
      • store.js


store.js

import Vue from 'vue';
import Vuex from 'vuex';
import todoApp from './modules/todoApp';

Vue.use(Vuex);

export const store = new Vuex.Store({
 modules: {
   todoApp
}
});


./modules/todoApp

const storage = {
    fetch() {
        const arr = [];
        if (sessionStorage.length > 0) {
            for (let i = 0; i < sessionStorage.length; i++) {
                if (sessionStorage.key(i) !== 'loglevel:webpack-dev-server') {
                    arr.push(JSON.parse(sessionStorage.getItem(sessionStorage.key(i))));
                }
            }
        }
        return arr;
    },
};

const state = {
   todoItems: storage.fetch(),
}

const getters = {
   storedTodoItems(state) {
       return state.todoItems;
  }
}

const mutations = {
   addOneItem(state, todoItem) {
       const obj = {completed: false, item: todoItem};
       sessionStorage.setItem(todoItem, JSON.stringify(obj));
       state.todoItems.push(obj);
  },
   removeOneItem(state, payload) {
       sessionStorage.removeItem(payload.todoItem.item);
       state.todoItems.splice(payload.index, 1);
  },
   toggleOneItem(state, payload) {
       state.todoItems[payload.index].completed = !state.todoItems[payload.index].completed;
       sessionStorage.removeItem(payload.todoItem.item);
       sessionStorage.setItem(payload.todoItem.item, JSON.stringify(payload.todoItem));
  },
   clearAll(state) {
       state.todoItems = [];
       sessionStorage.clear();
  }
}

export default { state, getters, mutations }
반응형

'Study > Vue.js' 카테고리의 다른 글

[Vue.js] 09 ES6  (0) 2021.09.24
[Vue.js] 07 SFC(Single File Component)  (0) 2021.09.24
[Vue.js] 05 Template  (0) 2021.09.23
[Vue.js] 03 Router  (0) 2021.09.23
[Vue.js] 02 Component  (0) 2021.09.23