Store를 모듈(module)로 사용하면 계층 구조로 Store를 관리할 수 있습니다.
namespaced의 여부에 따라 상위 모듈과 계층 되거나 중첩됩니다.
modules: {
A: {
namespaced: true,
state: {
stateA: 'A' --> this.$store.state.A.stateA
},
getters: {
getterA() { ... } --> this.$store.getters['A/getterA']
},
mutations: {
mutationA() { ... } --> this.$store.commit('A/mutationA')
},
actions: {
actionA() { ... } --> this.$store.dispatch('A/actionA')
},
modules: {
B: {
namespaced: true,
state: {
stateB: 'B' --> this.$store.state.A.B.stateB
},
getters: {
getterB() { ... } --> this.$store.getters['A/B/getterB']
},
mutations: {
mutationB() { ... } --> this.$store.commit('A/B/mutationB')
},
actions: {
actionB() { ... } --> this.$store.dispatch('A/B/actionB')
}
},
C: {
state: {
stateC: 'C' --> this.$store.state.A.C.stateC
},
getters: {
getterC() { ... } --> this.$store.getters['A/getterC']
},
mutations: {
mutationC() { ... } --> this.$store.commit('A/mutationC')
},
actions: {
actionC() { ... } --> this.$store.dispatch('A/actionC')
}
}
}
}
}
B 모듈은 네임스페이스가 있어 A 모듈과 부모(A)-자식(B)으로 계층 관계이고 C 모듈은 네임스페이스가 없어서 A 모듈과 중첩됩니다. 단, 모듈마다 state는 네임스페이와 상관없이 계층 관계가 됩니다.
Vuex 모듈 생성하기
1. C:\workspaces\nodeserver\testvue\src\store 폴더에 modules 폴더를 생성하고 score.js 파일을 생성합니다.
score.js 파일을 오픈하여 코딩합니다.
const scoreStore = {
namespaced: true
};
export default scoreStore;
namespaced가 true이면 모듈(module)이 독립적으로 사용됩니다.
false이면 모듈(module)의 state를 제외하고는 getters, mutations, actions는 전역으로 사용됩니다.
이전 C:\workspaces\nodeserver\testvue\src\store\index.js 파일에서 createStore에 있는 state, getters, mutations, actions를 복사하여 score.js 파일에 추가하고 index.js 파일에서는 삭제합니다.
const scoreStore = {
namespaced: true,
state: {
total: 0,
score: 0,
count: 3
},
getters: {
// 합계를 가져옵니다.
getTotal(state) {
return state.total;
},
// 점수를 가져옵니다.
getScore(state) {
return state.score;
},
// 카운트 문자열을 가져옵니다.
getCountString(state) {
return "현재 카운트가 " + state.count + "번 남았습니다.";
},
// 점수가 10이상이면 성공 문자열을 가져옵니다.
getTotalState(state, getters) {
if (state.count == 0) {
return getters.getTotal >= 10 ? "성공" : "실패";
}
}
},
mutations: {
// 카운트를 감소시킵니다.
decrementCount(state) {
state.count--;
},
// 점수를 랜덤으로 증가 시킵니다.
incrementTotalByRandom(state) {
const random = Math.floor(Math.random() * 10);
state.score = random;
state.total += random;
},
// 점수와 카운트를 초기화시킵니다.
reset(state) {
state.total = 0;
state.score = 0;
state.count = 3;
}
},
actions: {
// 점수를 처리합니다.
doScore({commit,state}) {
if (state.count > 0) {
commit('decrementCount');
commit('incrementTotalByRandom');
}
},
// 초기화합니다.
reset({commit}) {
commit('reset');
}
}
};
export default scoreStore;
2. index.js 파일에 score.js 파일을 import로 가져오고 modules에 scoreStore를 키(사용할 이름):값(import로 가져온 이름)으로 추가합니다.
import { createStore } from 'vuex';
import scoreStore from '@/store/modules/score.js';
export default createStore({
modules: {
scoreStore: scoreStore
}
});
3. C:\workspaces\nodeserver\testvue\src\views\Score.vue 파일의 <script>의 computed와 methods에 namespace인 "scoreStore"를 추가합니다.
<script>
export default {
name: 'Score',
computed: {
counter() {
return this.$store.getters['scoreStore/getCountString'];
},
total() {
return this.$store.state.scoreStore.total;
},
score() {
return this.$store.state.scoreStore.score;
},
totalState() {
return this.$store.getters['scoreStore/getTotalState'];
}
},
methods: {
doScore() {
this.$store.dispatch('scoreStore/doScore');
},
reset() {
this.$store.dispatch('scoreStore/reset');
}
}
};
</script>
namespaced가 false이면 모듈(module)의 state를 제외하고는 getters, mutations, actions는 전역으로 사용됩니다.
<script>
export default {
name: 'Score',
computed: {
counter() {
return this.$store.getters['getCountString'];
},
total() {
return this.$store.state.scoreStore.total;
},
score() {
return this.$store.state.scoreStore.score;
},
totalState() {
return this.$store.getters['getTotalState'];
}
},
methods: {
doScore() {
this.$store.dispatch('doScore');
},
reset() {
this.$store.dispatch('reset');
}
}
};
</script>
Vuex Helper 사용하기
mapState() 메서드는 모듈(module)의 state를 연결해 주는 메서드입니다.
mapGetters() 메서드는 모듈(module)의 getters를 연결해 주는 메서드입니다.
mapMutations() 메서드는 모듈(module)의 mutations를 연결해 주는 메서드입니다.
mapActions() 메서드는 모듈(module)의 actions를 연결해 주는 메서드입니다.
Object Spread Operator(객체 스프레드 오퍼레이터, "...")를 사용하면 state, getters, mutations, actions의 객체와 메서드를 복사되어 추가됩니다.
1. C:\workspaces\nodeserver\testvue\src\views\Score.vue 파일의 <script>에 vuex의 mapState() 메서드를 사용하기 위해 import로 추가합니다.
import { mapState } from 'vuex';
computed에 mapState() 메서드를 사용하여 scoreStore의 state를 가져옵니다. scoreStore의 namespaced가 true임으로 "scoreStore"를 첫 번째 인자로 전달해야 합니다.
scoreStore의 state에 있는 변수의 이름을 그대로 사용합니다.
...mapState('scoreStore', ['total', 'score']),
이름을 지정하여 사용하고 싶다면 {지정할 이름: state 변수 이름}으로 하면 됩니다. 콤마(,)로 여러 개를 선언할 수 있습니다.
...mapState('scoreStore', {totalNum:'total', scoreNum:'score'}),
여기서는 computed에 있는 메서드가 state와 동일한 이름으로 되어 있어 지정된 이름으로 처리하겠습니다.
computed에서 this.$store.state로 되어 있는 부분을
total() {
return this.$store.state.total;
},
score() {
return this.$store.state.score;
}
mapState() 메서드에서 가져와 지정한 이름으로 변경합니다.
total() {
return this.totalNum;
},
score() {
return this.scoreNum;
}
또는 computed에 있는 메서드가 state와 동일한 이름으로 되어 있어 computed에 있는 메서드를 삭제하면 됩니다.
...mapState('scoreStore', ['total', 'score']),
2. <script>에 vuex의 mapGetters() 메서드를 사용하기 위해 import에 추가합니다.
import { mapState, mapGetters } from 'vuex';
computed에 mapGetters() 메서드를 사용하여 scoreStore의 getters를 가져옵니다. scoreStore의 namespaced가 true임으로 "scoreStore"를 첫 번째 인자로 전달해야 합니다.
scoreStore의 getters에 있는 메서드 이름을 그대로 사용합니다.
...mapGetters('scoreStore', ['getCountString', 'getTotalState']),
이름을 지정하여 사용하고 싶다면 {지정할 이름:getters 메서드 이름}으로 하면 됩니다. 콤마(,)로 여러 개를 선언할 수 있습니다.
...mapGetters('scoreStore', {getCountStringText: 'getCountString', getTotalStateText: 'getTotalState'}),
computed에서 this.$store.getters로 되어 있는 부분을
counter() {
return this.$store.getters['getCountString'];
},
totalState() {
return this.$store.getters['getTotalState'];
}
mapGetters() 메서드에서 가져온 getters로 변경합니다.
counter() {
return this.getCountString;
},
totalState() {
return this.getTotalState;
}
또는 computed의 메서드 명으로 지정하고 computed에 있는 메서드를 삭제하면 됩니다.
...mapGetters('scoreStore', {counter:'getCountString', totalState:'getTotalState'})
3. <script>에 vuex의 mapActions() 메서드를 사용하기 위해 import에 추가합니다.
import { mapState, mapGetters, mapActions } from 'vuex';
methods에 mapActions() 메서드를 사용하여 scoreStore의 actions를 가져옵니다. scoreStore의 namespaced가 true임으로 "scoreStore"를 첫 번째 인자로 전달해야 합니다.
scoreStore의 actions에 있는 메서드 이름을 그대로 사용합니다.
...mapActions('scoreStore', ['doScore', 'reset']),
이름을 지정하여 사용하고 싶다면 {지정할 이름:actions 메서드 이름}으로 하면 됩니다. 콤마(,)로 여러 개를 선언할 수 있습니다.
...mapActions('scoreStore', {procScore:'doScore', procRest:'reset'}),
여기서는 methods에 있는 메서드가 actions과 동일한 이름으로 되어 있어 지정된 이름으로 처리하겠습니다.
methods에서 this.$store.dispatch로 되어 있는 부분을
doScore() {
this.$store.dispatch('doScore');
},
reset() {
this.$store.dispatch('reset');
}
mapActions() 메서드에서 가져와 지정한 이름으로 변경합니다.
doScore() {
this.procScore();
},
reset() {
this.procRest();
}
mapActions() 메서드에서 가져온 메서드는 dispatch() 메서드를 자동으로 처리해 주므로 dispatch() 메서드 없이 호출합니다.
또는 methods에 있는 메서드가 actions과 동일한 이름으로 되어 있어 methods에 있는 메서드를 삭제하면 됩니다.
methods: {
...mapActions('scoreStore', ['doScore', 'reset'])
}
수정된 score.js의 <script> 전체 소스입니다.
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
export default {
name: 'Score',
computed: {
...mapState('scoreStore', ['total', 'score']),
...mapGetters('scoreStore', {counter:'getCountString', totalState:'getTotalState'})
},
methods: {
...mapActions('scoreStore', ['doScore', 'reset'])
}
};
</script>
또는 getters와 actions만 사용하여 처리할 수 도 있습니다.
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'Score',
computed: mapGetters('scoreStore', {total:'getTotal', score:'getScore', counter:'getCountString', totalState:'getTotalState'}),
methods: mapActions('scoreStore', ['doScore', 'reset'])
};
</script>