// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
});
// main.js
import { store } from './store/store.js';
new Vue({
...,
store,
...
});
data()
template
methods
컴포넌트 -> 비동기 로직 -> 동기 로직 -> 상태
✅ 단방향이라는 것이 중요!!
data
computed
methods
async methods
// Vue
data: {
message: 'Hello Vue.js!'
}
// Vuex
state: {
message: 'Hello Vue.js!'
}
<!-- Vue -->
<p>{{ message }}</p>
<!-- Vuex -->
<p>{{ this.$store.state.message }}</p>
computed()
처럼 미리 연산된 값을 접근하는 속성// store.js
state: {
num: 10
},
getters: {
getNum(state) {
return state.num;
},
doubleNum(state) {
return state.num * 2;
}
}
<p>{{ this.$store.getters.getNum }}</p>
<p>{{ this.$store.getters.doubleNum }}</p>
commit()
으로 동작시킨다// store.js
state: { num: 10 },
mutations: {
printNum(state) {
return state.num;
},
sumNum(state, anotherNum) {
return state.num + anotherNum;
}
}
// App.vue
this.$store.commit('printNum');
this.$store.commit('sumNum', 20);
// store.js
state: { storeNum: 10 },
mutations: {
modifyState(state, payload) {
console.log(payload.str);
return state.storeNum += payload.num;
}
}
// App.vue
this.$store.commit('modifyState', {
str: 'passed from payload!!',
num: 20
});
methods: {
increaseCounter() { this.$store.state.counter++; }
}
특정 시점에 어떤 컴포넌트가 state를 접근하여 변경한 건지 확인하기 어렵기 때문
따라서, 뷰의 반응성을 거스르지 않게 명시적으로 상태 변화를 수행.
반응성, 디버깅, 테스팅 혜택
dispatch()
로 동작시킨다아래는 actions에서 mutations를 사용할 때의 흐름을 확인해 볼 수 있는 코드이다
// store.js
state: {
num: 10
},
mutations: {
doubleNum(state) { // 3️⃣
return state.num * 2;
}
},
actions: {
delayDoubleNum(context) { // 2️⃣ context로 store의 메서드와 속성에 접근
context.commit('doubleNum');
}
}
// App.vue
this.$store.dispatch('delayDoubleNum'); // 1️⃣
// store.js
mutations: {
addCounter(state) {
state.counter++;
}
},
actions: {
delayedAddCounter(context) {
setTimeout(() => context.commit('addCounter'), 2000);
}
}
// App.vue
methods: {
incrementCounter() {
this.$store.dispatch('delayedAddCounter');
}
}
// store.js
mutations: {
setData(state, fetchedData) {
state.product = fetched.Data;
}
},
actions: {
fetchProductData(context) {
return axios.get('https://domain.com/products/1')
.then(response => context.commit('setData', response));
}
}
// App.vue
methods: {
getProduct() {
this.$store.dispatch('fetchProductData');
}
}
[그림] 여러 개의 컴포넌트에서 mutations로 시간 차를 두고 state를 변경하는 경우
// store.js
export const store = new Vuex.store({
state: { ... },
getters: { ... },
mutations: { ... },
actions: { ... }
});
위 코드를 모듈화 하면 아래처럼 작성할 수 있다
/// store.js
import * as getters from 'store/getters.js';
import * as mutations from 'store/mutations.js';
import * as actions from 'store/actions.js';
export const store = new Vuex.store({
state: { ... },
getters, // getters: getters,
mutations, // mutations: mutations
actions // actions: actions
});
modules
속성 사용import Vue from 'vue';
import Vuex from 'vuex';
import todo from 'modules/todo.js';
export const store = new Vuex.Store({
modules: {
moduleA: todo, // 모듈 명칭 : 모듈 파일 이름
}
});
// todo.js
const state = { ... };
const getters = { ... };
const mutations = { ... };
const actions = { ... };
// 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']) }
};
// store.js
state: {
num: 10
}
// App.vue
import { mapState } from 'vuex';
computed: {
...mapState(['num'])
}
<!-- <p>{{ this.$store.state.num }}</p> -->
<p>{{ this.num }}</p>
// store.js
getters: {
reverseMessage(state) {
return state.msg.split('').reverse().join('');
}
}
// App.vue
import { mapGetters } from 'vuex';
computed: { ...mapGetters(['reverseMessage']) }
<!-- <p>{{ this.$store.getters.reverseMessage }}</p> -->
<p>{{ this.reverseMessage }}</p>
// store.js
mutations: {
clickBtn(state) {
alert(state.msg);
}
}
// App.vue
import { mapMutations } from 'vuex';
methods: {
...mapMutations(['clickBtn']),
authLogin() {},
displayTable() {}
}
<button @click="clickBtn">popup message</button>
// store.js
state: { storeNum: 10 },
mutations: {
modifyState(state, payload) {
console.log(payload.str);
return state.storeNum += payload.num;
}
}
// App.vue
import { mapMutations } from 'vuex';
methods: {
// 인자를 작성하지 않아도 호출할 때 인자가 있다면 암묵적으로 넘겨준다
...mapMutations(['modifyState'])
}
<button @click="modifyState({str, num})"></button>
// store.js
actions: {
delayClickBtn(context) {
setTimeout(() => context.commit('clickBtn'), 2000);
}
}
// App.vue
import { mapActions } from 'vuex';
methods: {
...mapActions(['delayClickBtn']),
}
<button @click="delayClickBtn">delay popup message</button>
// 배열 리터럴
...mapMutations([
'clickBtn'
])
// 객체 리터럴
...mapMutations({
popupMsg: 'clickBtn' // 컴포넌트 methods 이름 : Store의 mutations 이름
})