개발 일기

[Vue.js] Vuex 요점 정리

권쓰 2018. 12. 27. 15:33
728x90

Vuex ?


Vue.js  상태관리  위한 패턴이자 라이브러리. 다른 상태관리 패턴이나 라이브러리와 비교했을 Vue Reactivity 체계를 효율적으로 활용하여 화면 업데이트가 가능하다는 차이점이 있다.


상태관리 (State Management) 필요한가?

컴포넌트 기반 프레임워크에서는 화면 구성을 위해 화면 단위를 매우 잘게 쪼개서 컴포넌트로 사용한다. 예를 들면, header, button, list 등의 작은 단위들이 컴포넌트가 되어 화면에서 많은 컴포넌트를 사용하게 된다. 이에 따라 컴포넌트 간의 통신이나 데이터 전달을 유기적으로 관리할 필요성이 생긴다.

달리 말해, header -> button, button -> list , button -> footer 등의 컴포넌트 데이터 전달 이벤트 통신 등의 여러 컴포넌트의 관계를 곳에서 관리하기 쉽게 구조화 하는 것이 State Management.

Vue 성격이 유사한 프론트엔드 프레임워크인 React 에서는 이미 Redux, Flux 같은 상태 라이브러리를 사용하고 있고, Vue Vuex 라는 상태관리 라이브러리를 사용한다.


상태관리로 해결할 있는 문제점?

상태관리는 중대형 규모의 컴포넌트들을 효율적으로 관리하기 위한 기법이다. 일반적으로 앱의 규모가 커지면서 생기는 문제점들은 아래와 같다.

  1. Vue 기본 컴포넌트 통신방식인 상위 - 하위 에서 중간에 거쳐야 컴포넌트가 많아지거나
  2. 이를 피하기 위해 Event Bus 활용하여 상하위 관계가 아닌 컴포넌트 통신 관리가 되지 않는

이러한 문제점들을 해결하기 위해 모든 데이터 통신 (state) 곳에서 중앙 집중식으로 관리한다.




상태관리 패턴

상태관리 구성요소는 크게 3가지가 있다.

  • state : 컴포넌트 공유될 data
  • view : 데이터가 표현될 template
  • actions : 사용자의 입력에 따라 반응할 methods

new Vue({

  // state

  data () {

    return {

      count: 0

    }

  },

  // view

  template: `

    <div>{{ count }}</div>

  `,

  // actions

  methods: {

    increment () {

      this.count++

    }

  }

})

Js

Copy


구성요소는 아래와 같이 동작한다.




Vuex 튜토리얼 #1 - 간단한 Vue App 구성

Vuex 적용을 위해 Parent 컴포넌트와 Child 컴포넌트를 갖는 간단한 앱을 아래처럼 만들었다.




컴포넌트 폴더구조는 아래와 같다.






  • App.vue : Parent 컴포넌트 또는 상위 컴포넌트
  • Child.vue : Child 컴포넌트 또는 하위 컴포넌트


앱의 특징은 아래와 같다.


Parent 컴포넌트 (App.vue) 코드부터 보면


<!-- Parent (App.vue) Template -->

<div id="app">

  Parent counter : {{ count }} <br>

  <button @click="addCounter">+</button>

  <button @click="subCounter">-</button>

 

  <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props 전달한다. -->

  <child v-bind:passedCounter="counter"></child>

</div>

HTML

Copy

// App.vue

import Child from './Child.vue'

 

export default {

  data () {

    return {

      // data 속성 등록

      counter: 0

    }

  },

  methods: {

    // 이벤트 추가

    addCounter() {

      this.counter++;

    },

    subCounter() {

      this.counter--;

    }

  },

  components: {

    // Child 컴포넌트를 하위 컴포넌트로 등록

    'child': Child

  }

}

React JSX

Copy


코드에서는 data 속성을 선언하고, 해당 data 속성을 증가 감소 시키는 이벤트를 등록하였다.


다음으로 Child 컴포넌트 코드를 보면,


<!-- Child (Child.vue) Template -->

<div>

  <hr>

  Child counter : {{ passedCounter }} <br>

  <button>+</button>

  <button>-</button>

</div>

HTML

Copy

// Child.vue

export default {

  // Parent 에서 넘겨준 counter 속성을 passedCounter 받음

  props: ['passedCounter']

}

Js

Copy

template 경우 구분선을 제외하고는 Parent 컴포넌트와 동일한 코드고, js 경우 전달받은 counter  props  등록하였다.


Vuex 튜토리얼 #2 - Vue App 분석

앱의 + 버튼을 클릭하면 Parent Child 컴포넌트의 숫자가 동일하게 올라간다.




이유는 Parent  counter  Child 에서 props  넘겨 받았기 때문이다.




달리 말해동일한 데이터 속성을 단지 2 개의 컴포넌트에서 동시에 접근하여 같은 값을 표현하고 있는 것이다.

구조는 Vue props 이용한 기본적인 Parent - Child 컴포넌트 통신이다. 화면의 단위를 잘게 쪼개면 쪼갤수록 컴포넌트의 데이터를 다른 컴포넌트의 화면에서 표시할 일이 많아진다. 여기서 컴포넌트의 갯수가 무한정 많아진다면? 천재가 아닌 이상 이걸 기억할 수도 없고, 가장 중요한 것은 협업하는 입장에서는 소스를 일일이 까봐야 추적이 가능하다.

이런 비효율적인 컴포넌트 통신 관리를 Vuex 해결해보자.



Vuex 튜토리얼 #3 - Vuex 설치 등록

아래 명령어로 Vuex 설치하자.


npm install vuex --save

Shell

Copy


그리고 Vuex 등록할 js 파일을 하나 새로 생성한다. 이름은 관례에 따라 store.js  지정한다.


// store.js

import Vue from 'vue'

import Vuex from 'vuex'

 

Vue.use(Vuex);

 

export const store = new Vuex.Store({

  //

});

Js

Copy

그리고 Vue App 등록된 main.js  넘어가서 store.js  불러와 등록하면 된다.

// main.js

import Vue from 'vue'

import App from './App.vue'

// store.js 불러와

import { store } from './store'

 

new Vue({

  el: '#app',

  // Vue 인스턴스에 등록한다.

  store,

  render: h => h(App)

})

Js

Copy


Vuex 튜토리얼 #4 - state 등록

state Vuex 아래와 같이 추가할 있다.


// store.js

import Vue from 'vue'

import Vuex from 'vuex'

 

Vue.use(Vuex);

 

export const store = new Vuex.Store({

  // counter 라는 state 속성을 추가

  state: {

    counter: 0

  },

});

Js

Copy


state 정의된 counter 속성은 Parent 컴포넌트 에서 사용하던 data 속성 counter  동일한 역할을 한다. 이미  상태관리 패턴 챕터 에서 설명했듯이 “state 컴포넌트 간에 공유할 data 속성을 의미한다.”


Vuex 튜토리얼 #5 - state 접근

방금 state 등록한 counter  앱에서 접근하려면 this.$store.state.counter  활용한다. 앞의 App.vue Vuex 맞게 다시 정리하면


<div id="app">

  Parent counter : {{ this.$store.state.counter }} <br>

  <button @click="addCounter">+</button>

  <button @click="subCounter">-</button>

 

  <!-- 기존 코드 -->

  <!-- <child v-bind:passedCounter="counter"></child> -->

  <child></child>

</div>

HTML

Copy

// App.vue

import Child from './Child.vue'

 

export default {

  // 기존 코드

  // data () {

  //   return {

  //     counter: 0

  //   }

  // },

  methods: {

    addCounter() {

      this.$store.state.counter++;

    },

    subCounter() {

      this.$store.state.counter--;

    }

  },

  components: {

    'child': Child

  }

}

Js

Copy


기존 코드와의 차이점은

  1. data 속성으로 선언한 counter 제거
  2. Child 컴포넌트로 counter 전달하지 않음

결국 Parent 에서 관리하던 counter 라는 데이터를 Vuex state 넘겨준 것이다. Child 컴포넌트에서 접근하던 Parent 컴포넌트의 data Vuex 갔기 때문에, 이제 Child Parent 모두 Vuex state 바라본다.따라서, Vuex 라는 저장소의 데이터를 모든 컴포넌트들이 동일한 조건에서 접근하여 사용하게 된다.


화면상으로는 이전과 차이가 없지만 내부적으로는 Vuex 데이터 관리를 하고 있는 차이가 있다.

동일하게 Child 컴포넌트의 코드에도 Vuex 반영해보면

<div>

  <hr>

  Child counter : {{ this.$store.state.counter }} <br>

  <button>+</button>

  <button>-</button>

</div>

HTML

Copy

export default {

  // 기존 코드

  // props: ['passedCounter']

}

Js

Copy


Parent 컴포넌트 에서 props  counter  전달받던 방식에서, Vuex state  counter  바로 접근하는 방식으로 변경됐다.


마무리


위와 같이 Vuex state 이용하여 데이터 관리를 곳에서 효율적으로 있다.

이외에도 변경된 state 값을 받아오기 위한 Getters, state 값을 변경하기 위한 Mutations, 비동기 mutations 로직을 위한 Actions, 폴더 구조화 등을 알아야 Vuex 활용하여 가독성 있는 코드를 있다.

 



출처 : 캡틴판교님 블로그 https://joshua1988.github.io/web-development/vuejs/vuex-start/