💡 Vuex는 Vue.js에서 사용하는 상태 관리 저장소 라이브러리입니다. 모든 Vue Component에서 접근 가능한 이 상태 관리 저장소는 모든 데이터의 흐름을 중앙에서 관리할 수 있다는 편리함을 제공하는데요, 오늘은 이 Vuex의 흐름과 규칙에 대해서 정리해보도록 하겠습니다.

Vuex의 기본 흐름

Vuex를 검색하면 가장 먼저 나오는 이 흐름도를 많이 접하셨을 것같아요. 그런데 저는 처음에 이 그림이 도통 이해가 안가더라구요..😅 제가 이해한 내용을 바탕으로 최대한 이해하기 쉽게 설명드리겠습니다!

일단 크게 이 3가지만 알고 계시면 됩니다!

  • State(상태)
  • Mutation(변이)
  • Actions(액션)


State(상태)

각각의 Component에서 필요한 데이터를 꺼내다 쓸 수 있어야겠죠? 그런데 우리 개발해보면 느끼셨을지 모르겠지만, 원본데이터를 유지하는게 중요하잖아요. 그 원본 데이터가 바로 State입니다!

const store = new Vuex.Store({
  state: {
    count: 0;
  }
});


우리 그러면 State를 Component로 가져다가 사용하는 법도 알아야겠죠? 아주 간단합니당! computed에서 가져다가 사용하면 됩니다. 형식은 this.$store.state.stateName 다음처럼 작성해주시면 됩니다! 그러면 State 값에 변화가 있을 때마다 computed에서 자동으로 계산이 되어서 변경된 값으로 화면에 출력이 될 것입니다. 너무 좋죠?

export default {
  computed: {
    count() {
      return this.$store.state.count;
    }
  }
}


Mutation(변이)

제가 Vuex를 처음 접할 때 가장 어렵고 이해하기 어려웠던 것이 Mutation이에요. 제대로 사용 못해서 이전에 작성했던 코드를 보면 엉망인 부분도 있답니다..😅 볼때마다 부끄러워서 얼른 수정해야겠어요!

Mutation(변이)는 Vuex 스토어에서 State를 변경할 수 있는 유일한 방법입니다. 위에서 설명했듯이 State는 원본 데이터라고 했죠? 이 데이터를 바꿔줄 수 있는 유일한 아이가 바로 이 Mutation(변이)입니다! 이 방법 외에 값을 자체적으로 바꿀 수도 있지만 좋지 않은 방법이고 규칙을 무시하는거라서 웬만하면 Mutation(변이)를 이용해서 수정해보도록 합시다! Redux의 Reducer가 비슷한 역할을 한다고 생각해요.

const store = new Vuex.Store({
  state: {
    count: 0;
  },

  mutation: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    }
  }
});


우리 그러면 Mutation을 Component로 가져다가 사용하는 법도 알아봐요! Mutation은 State와는 다르게 직접 호출하지 않고 commit 메소드를 사용합니다. this.$store.commit('Mutation 메소드 명')처럼요!


왜 commit이냐?

commit이라는 용어는 변경을 확정한다는 뜻입니다. 저희 git을 사용할 때 저장소에 변경된 내용을 commit하잖아요? 그거랑 연관지어 생각해보면 이해가 확 되지않나요? 히히 :)
<template>
  <div>
    <button @click="store.commit('increment')">증가</button>
    <button @click="store.commit('decrement')">감소</button>
  </div>
</template>

<script>
  export default {
    computed: {
      count() {
        return this.$store.state.count;
      }
    }
  }
</script>


🚨 주의 Mutation(변이)핸들러 함수는 반드시 동기적 이어야 합니다! 그러면 비동기처리는 어디서 하느냐? 바로 다음 Actions에서 살펴봅시다!


Actions(액션)

저는 처음에 이 Actions(액션)을 사용해서 State를 변경시키는 것! 이라고 생각을 했었어요. 그런데 Actions는 모든 과정이 끝났을 때 Mutation(변이)에 대한 commit을 진행하는 것이래요. 아까 우리 commit이 뭐라고 했죠?! 변경 내용을 확정시키는 일!!!

그래서 Actions에서 모든 비동기 처리를 마치고 그 결과를 Mutation(변이)로 commit을 해서 Vuex 스토어의 데이터를 업데이트 시켜줍니다.

const state = {
  ...

  user: {
    loggedIn: false,
    data: {}
  }
}

...

const mutations = {
  ...

  SET_USER(state, data) {
      state.user.data = data
  }
}

...

const actions = {
    fetchUser({ commit }, user) {
      if (user) {
        this.state.uid = user.uid;
        axios.get('/api/read/' + user.uid)
          .then(async response => {
            await commit("SET_USER", {
              uid: user.uid,
              phoneNumber: user.phoneNumber,
              displayName: response.data.displayName,
              email: response.data.email,
            })
          })
      } else {
        commit("SET_USER", null);
      }
    },
}

다음 코드는 제가 작업을 진행했던 코드로, 사용자의 정보가 있다면 payload를 가진 SET_USER라는 mutations에 대한 commit을 진행한 것입니다.

payload 란?

그냥 단순하게 commit에서 전달된 매개변수 입니다. 대부분의 payload는 여러 필드를 포함할 수 있는 객체(Object) 형태로 전달이 됩니다.


Getters(게터)

우리 이제 Vuex의 3가지 컨셉에 대해서는 모두 살펴보았습니다! 👏👏👏 그런데 아직 하나 더 남았어용..ㅎㅎ 마지막으로 Getters(게터)입니다.

Getters(게터)는 단순하게 Component에서 본 computed 속성과 같은 역할을 합니다. State를 직접 사용하는 것이 아닌, State를 이용해서 계산된 속성을 가져다가 사용하는 것이죠! 이러면 자연스럽게 State 값이 변경되면 변경된 계산 결과 값을 가질 수 있을거에요!

const store = new Vuex.Store({
  ...

  getters: {
    duckCount(state) {
      return state.ducks.length;
    }
  }
});



Vuex의 장점

애플리케이션에서 사용하고 있는 데이터의 흐름을 추적 하기가 매우 직관적이고 편리하다는 것! 언제 어떤 데이터가 변이되었는지를 확인할 수 있었잖아요! 그래서 이걸 시간여행 디버깅이라고도 한대요ㅎㅎ 표현이 너무 귀엽죠?? :)