[Vue 3] Vuex란?


Vue.js의 상태 관리를 위한 라이브러리, Vuex를 사용해보자!

vuex는 간단하게 저장소라고 생각하면 된다. 상태를 저장하고 이 상태를 변경하는 일을 수행할 수 있으며, 컴포넌트간의 데이터 전달을 관리한다고 보면 되겠다.

⛳ 설치 및 기본 환경 설정


veux는 아래의 명령어를 통해 설치 가능하다. (버전 확인은 package.jason에서 가능)

npm install vuex

설치한 후 프로젝트/src하위 경로에 store 폴더를 생성하고 그 안에 index.js를 만들어주자.

// 폴더구조
src
├── store
│   └── index.js
├── components
├── views
├── App.vue
└── main.js

📝 main.js에 store 등록하기


이제 main.js에서 store를 import한 뒤에 use(store) 해주자. (vue3 버전)

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { store } from "./store"; // store 등록!

createApp(App).use(router, store).mount('#app')

🐟 이제 본격적으로 vuex에 대해서 알아보자!


vue3 버전은 vuex 4버전을 사용해야 한다! ‘Vuex’ is not defined 오류 포스팅 참고

이유는 모르겠는데 export default new Veux.Store({})로 적으면 'Vuex' is not defined라는 에러가 뜬다.. 아무리 찾아도 원인은 안나오고, stackoverflow에 달린 답글 중 하나는 export const store = new Vuex.Store({})를 사용해보라는 것이었는데, 이러면 오류는 안뜬다. 🤔

참고로, vuex 3에서는 아래와 같이 사용 가능

// store/index.js
import Vue from "vue"
import Vuex from "vuex"
import axios from "axios"

Vue.use(Vuex);

export default new Veux.Store({ })

vuex 4부턴 이렇게!

export const store = createStore()을 통해 사용해야한다.

// store/index.js
import { createStore } from 'vuex'
import axios from 'axios'
// 라우터랑 동일한 방식으로 export
export const store = createStore ({
  state: {
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
})

Vuex의 핵심 컨셉은 위에 나와있는 4가지, state(상태), getters, mutations(변이), actions(액션)이다. *예제 코드는 로그인을 위해 작성했던 코드를 첨부했다.

state

먼저 state에는 앱의 상태가 들어간다. 로그인을 예시로 들면, accessToken이 하나의 상태이며, 이 값은 사용자가 로그인을 하는 동안 아이디가 존재하는지 확인하고 서버에서 토큰을 넘겨줌에 따라 상태가 변한다. Vue 컴포넌트에서의 접근은 this.$store.state.accessToken과 같이 할 수 있다.

getters

다음으로 getters는 state를 계산할 수 있다. 첫 번째 인자로 state를 받고 두 번째 인자로는 다른 getters도 받을 수도 있다. 컴포넌트에서는 this.$store.getters.지정한 함수 이름을 통해 사용 가능하다.

mutation

어쩌면 가장 중요한, muatation(변이)은 실제로 상태를 변경한다. vuex 저장소의 state를 변경하는 변이는 이벤트와 유사하다. 각 변이에는 핸들러가 존재하고, 이 핸들러 함수가 상태를 수정한다. 핸들러 함수는 첫 번째 인자로 state를 받는다. 또한 추가 인자로 payload라고 하는 store.commit을 사용할 수 있다.

// store/index.js
  mutations: {
    LOGIN(state, { accessToken }) {
      // { accessToken }은 서버에서 넘겨주는 값
      state.accessToken = { accessToken }
    },

    LOGOUT(state) {
      // 로그아웃 시에는 토큰을 null로 초기화해준다.
      state.accessToken = null
    },
  },

중요한 점은 mutation의 핸들러 함수는 무조건 동기적이라는 것이다. 여기서 변이와 액션의 차이점이 생긴다.

action

마지막으로 action은 mutation이랑 비슷하지만, 상태를 변이시키는게 아니고 액션으로 변이에 대한 커밋을 한다. 또한 앞서 말했듯이 비동기 작업이 가능하다. 인자로는 함수와 속성 세트를 가진 context 객체를 받으며, context.commit이나 context.getters를 통해 접근할 수 있다. 이때, commit을 여러번 호출해야 하는 경우 등에서 코드 단순화를 위해 전달인자 분해를 사용한다. (commit 같은 경우, { commit })

액션은 컴포넌트에서 this.$store.dipatch("LOGIN", { user_id, user_pw })으로 호출된다.

Q. 그냥 store.commit(‘LOGIN’)하면 안되나요?

A. 비동기 작업을 수행하기 위함이며, store.commit()을 직접 호출한다면 동기적으로 상태가 변이된다.

정리: 액션에서 비동기적으로 필요한 일들을 쭉 수행 -> 이후 상태변이를 마지막에 기록

// store/index.js
actions: {
    LOGIN({ commit }, { user_id, user_pw }) {
      return axios
        .post('/api/auth/login', { user_id, user_pw })
        .then(({ data }) => commit("LOGIN", data))
    },
    LOGOUT({ commit }) {
      commit("LOGOUT")
    },
  },

이외에도 모듈을 통해 저장소를 나눌 수 있다. 자세한건 공식문서를 참고하자.




# 카테고리