📦 Vuex의 구조 완전 정복 - State, Mutation, Action, Getter
Vue 상태 관리 시리즈 > 5️⃣ Vuex / Pinia 상태 관리 > 2️⃣ Vuex의 구조 (State, Mutation, Action, Getter)
- 0. Vuex 구조와 핵심 개념
- 1. State - 중앙 집중식 상태
- 2. Mutation - 상태 변경의 유일한 방법
- 3. Action - 비동기 로직 처리
- 4. Getter - 파생 상태 계산
- 5. 전체 흐름 요약
- 6. 실전 팁 & 주의사항
- 🔚 마무리 & 다음 글 안내
0. Vuex 구조와 핵심 개념
Vuex는 전역 상태 저장소입니다. 모든 컴포넌트에서 상태를 공유할 수 있으며, 상태의 흐름이 명확해집니다.
(createStore로 넘기는 인자 속성명은 Vuex에서 예약된 이름이기 때문에 IDE도움을 받아서 오타를 나지 않도록 작성해야합니다.)
개념 | 역할 |
State | 애플리케이션에서 공유할 전역 상태 (데이터) |
Mutation | state를 동기적으로 수정하는 함수 (commit) |
Action | 비동기 로직 포함 가능, mutation을 호출하는 함수 (dispatch) |
Getter | state를 계산하여 반환하는 computed 같은 역할 |
1. State - 중앙 집중식 상태
Vuex의 state
는 애플리케이션의 모든 컴포넌트에서 공유되는 단일 상태 트리입니다. 이는 전역 변수처럼 작동하지만, Vue의 반응성 시스템과 통합되어 상태 변경 시 자동으로 UI가 업데이트됩니다. 상태는 모든 컴포넌트에서 공유되며, 단일 소스의 진실(Single Source of Truth)로 작용합니다.
new Vuex.Store() 방식은 Vue 2 + Vuex 3 , 클래스 기반 방식. ( this.$store.state.count으로 접근)
createStore() 방식은 Vue 3 + Vuex 4, 함수 기반 방식이어서 이 방식으로 쓰는게 좋음. Vue3에서 new Vuex.Store() 방식은 권장되지 않음. (state, mutations, actions , getters 구조는 그대로 사용.)
// store/index.js
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
doubleCount: state => state.count * 2
}
});
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
createApp(App).use(store).mount('#app');
// 컴포넌트에서 사용
<template>
<div>
{{ count }}
<button @click="increment">+1</button>
<button @click="incrementAsync">+1 비동기</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
computed: {
...mapState(['count'])
},
methods: {
...mapActions(['incrementAsync']),
increment() {
this.$store.commit('increment');
}
}
}
</script>
2. Mutation - 상태 변경의 유일한 방법
mutation
은 Vuex 상태를 변경하는 유일한 방법입니다.( state를 변경하는 메서드 ) 각 mutation은 문자열 타입과 핸들러 함수로 구성되며, 상태 변경은 반드시 동기적으로 이루어져야 합니다. mutation 메서드는 상태 변경을 추적하고 디버깅하기 쉽게 만듭니다.
export default createStore({
state: { count: 0 },
mutations: {
increment(state) {
state.count++;
},
setUserName(state, name) {
state.user.name = name;
}
}
});
컴포넌트에서 접근 시 Options API 에서는 this.$store.commit('increment')
와 같이 mutation 호출하여 상태를 변경합니다.
Composition API 에서는 useStore()
를 통해 접근합니다. 아래도 모두 동일
// Composition API
import { useStore } from 'vuex';
setup() {
const store = useStore();
store.commit('increment'); // mutation 호출
store.dispatch('fetchData'); // action 호출
}
3. Action - 비동기 로직 처리
action
은 비동기 작업을 처리하고, 그 결과로 mutation을 커밋하여 상태를 변경합니다. 예를 들어, API 호출 후 데이터를 받아와 상태를 업데이트할 때 사용됩니다.
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
}
});
컴포넌트에서 action을 호출하려면 컴포넌트에서 this.$store.dispatch('incrementAsync')
와 같이 action을 호출하여 비동기 작업을 실행합니다.
4. Getter - 파생 상태 계산
getter
는 state를 기반으로 계산된 값을 반환하는 함수입니다. 이는 컴포넌트의 computed 속성과 유사하게 작동하며, 캐싱되어 성능 최적화에 도움이 됩니다.
export default createStore({
state: {
todos: [
{ id: 1, text: '할 일 1', done: true },
{ id: 2, text: '할 일 2', done: false }]
},
getters: {
doneTodos(state) {
return state.todos.filter(todo => todo.done);
},
doneTodosCount(state, getters) {
return getters.doneTodos.length;
}
}
});
컴포넌트에서 this.$store.getters.doneTodosCount
와 같이 접근하여 계산된 값을 사용할 수 있습니다.
5. 전체 흐름 요약
Vuex의 데이터 흐름은 다음과 같습니다:
- 컴포넌트에서
dispatch
를 통해 action을 호출합니다. - action은 비동기 작업을 수행한 후,
commit
을 통해 mutation을 호출합니다. - mutation은 state를 변경합니다.
- 변경된 state는 getter를 통해 계산된 값으로 제공되며, 컴포넌트는 이를 사용하여 UI를 업데이트합니다.
6. 실전 팁 & 주의사항
- state 직접 변경 금지: state는 mutation을 통해서만 변경해야 합니다. 직접 변경하면 Vue DevTools에서 추적이 어렵습니다.
- mutation은 동기적: 비동기 작업은 action에서 처리하고, mutation은 상태 변경만 담당해야 합니다.
- getter는 캐싱됨: getter는 캐싱되어 성능에 유리하지만, 인자를 받는 함수형 getter는 매번 실행됩니다.
- 모듈화: 애플리케이션이 커지면 store를 모듈로 나누어 관리하는 것이 좋습니다.
🔚 마무리 & 다음 글 안내
이번 글에서는 Vuex의 핵심 구성 요소인 state, mutation, action, getter에 대해 알아보았습니다. 다음 글에서는 Pinia로 마이그레이션 하기를 주제로 Vuex에서 Pinia로의 전환 방법과 장단점에 대해 다룰 예정입니다.
👉 다음 글: Pinia로 마이그레이션 하기
'framework_library > vue' 카테고리의 다른 글
📦 Vue 상태 관리 - 모듈 분리와 Store 컴포지션 패턴 (0) | 2025.05.05 |
---|---|
📦 Vuex에서 Pinia로 마이그레이션 하기 (0) | 2025.05.05 |
📦 상태 관리가 필요한 이유와 Vuex 구조 이해하기 (0) | 2025.05.05 |
🚦 Vue Router - 라우트 중첩과 Lazy Loading 적용하기 (0) | 2025.05.05 |
🚦 Vue Router - 네비게이션 가드와 인증 처리 (0) | 2025.05.05 |
댓글