16. Vuex

vuex 를 이용하여 글로벌하게 state 를 관리하는 방법을 학습합니다.

Vuex 란 ?

글로벌하게 state 를 관리할 수 있도록 도와주는 상태관리 라이브러리입니다.

왜 vuex 가 필요한가요 ?

1. 형제끼리의 state 교환이 불가능합니다

일반적인 vue state 의 흐름으로는 형제끼리의 데이터 교환이 불가능합니다. 그렇기 때문에 이런 상황에는 두 컴포넌트를 감싸고 있는 부모 컴포넌트로 state 를 올려서 사용하게됩니다.

2. props 의 깊이가 깊어질 경우

1번에서 살펴본것처럼 state 를 부모로 올렸더라도 해당 데이터를 원하는 컴포넌트의 깊이가 깊어질수록 props 를 내려주는것이 힘들고 복잡해집니다.

3. 액션에 따라 동시에 바뀌는 컴포넌트들

버튼이 클릭되었을때 여러 컴포넌트들에 동시에 영향을 주는 경우가 있다면 vuex 도입을 고려해봄직합니다.

실습

(예제는 이전의 초기 구성되었던 환경에서 시작합니다.)

vuex 의 흐름은 아래와 같습니다. 크게 state, getters, mutations, actions 로 나뉩니다.

  • state: 관리할 상태 값들

  • getters: 밖으로 내보낼 값들 (실제 컴포넌트에서 가져가 사용할 값들)

  • mutations: 실제 state 가 변화되는곳

  • actions: mutations 을 일으키는곳 (state 변화 x)

컴포넌트에서 state 를 가져오기 위해서는 getters 를 이용하고 state 에 변화를 주기 위해서는 actions 를 이용합니다.

먼저 vuex 를 설치합니다

$ npm i --save vuex 

Store 정의

// src/store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    // 글로벌로 관리될 상태 값 
    counter: 0
  },
  getters: {
    // 데이터에 변화를 줄 순 없다.
    counter: state => state.counter
  },
  mutations: {
    // 실제 데이터 변화가 일어나는 곳
    increment: state => (state.counter += 1),
    decrement: state => (state.counter -= 1)
  },
  actions: {
    // mutaion 을 일을키위한 행동, 컴포넌트에서는 actions 를 사용한다
    addCounter: context => context.commit("increment"),
    subCounter: context => context.commit("decrement")
  }
});

vue 는 아직 vuex 의 존재를 모르기 때문에 vue 객체가 생성될때 해당 store 의 존재를 알려줘야합니다.

// main.js

import Vue from "vue";
import App from "./App.vue";
import store from "./store";

Vue.config.productionTip = false;

new Vue({
  store,
  render: h => h(App)
}).$mount("#app");

컴포넌트 구성

왼쪽 컴포넌트를 -, + 버튼을 노출하고 오른쪽 컴포넌트에는 현재 값을 표현하도록하고 싶습니다. 왼쪽 컴포넌트에서는 버튼을 누를때마다 actions 을 일으켜 해당 mutation 을 일으킵니다. 오른쪽 컴포넌트에서는 getter 를 이용하여 counter 값을 노출합니다.

먼저 Left 컴포넌트를 준비합니다. vuex 의 action 에 접근하기 위해서는 vuex 에서 제공해주는 mapActions 라는 함수를 이용합니다.

// components/Left.vue

<template>
  <div>
    <button @click="subCounter">-</button> // vuex 의 action 을 일으킵니다
    <button @click="addCounter">+</button>
  </div>
</template>

<script>
import { mapActions } from "vuex";

export default {
  methods: {
    ...mapActions(["addCounter", "subCounter"])
  }
};
</script>

<style>
</style>

다음은 Right 컴포넌트를 준비합니다. getter 에 접근하기 위해서는 vuex 에서 제공해주는 mapGetters 를 이용합니다.

// components/Right.vue 

<template>
  <div>value: {{ counter }}</div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters(["counter"])
  }
};
</script>

<style>
</style>

마지막으로 App.vue 에서 컴포넌트들을 불러옵니다.

// App.vue

<template>
  <div>
    <Left />
    <Right />
  </div>
</template>

<script>
import Left from "./components/Left";
import Right from "./components/Right";

export default {
  components: {
    Left,
    Right
  }
};
</script>

<style>
</style>

Last updated