본문 바로가기
framework_library/vue

📦 Vuex의 구조: State, Mutation, Action, Getter

by 죄니안죄니 2025. 5. 5.

📦 Vuex의 구조 완전 정복 - State, Mutation, Action, Getter

Vue 상태 관리 시리즈 > 5️⃣ Vuex / Pinia 상태 관리 > 2️⃣ Vuex의 구조 (State, Mutation, Action, Getter)

 

 


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의 데이터 흐름은 다음과 같습니다:

  1. 컴포넌트에서 dispatch를 통해 action을 호출합니다.
  2. action은 비동기 작업을 수행한 후, commit을 통해 mutation을 호출합니다.
  3. mutation은 state를 변경합니다.
  4. 변경된 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로 마이그레이션 하기

댓글