Vuex란?
Vue.js의 상태 관리를 위한 패턴이자 라이브러리입니다. 다른 상태 관리 패턴이나 라이브러리와 비교했을 때 뷰의 반응성(Reactivity) 체계를 효율적으로 활용하여 화면을 업데이트한다는 차이점이 있습니다.
상태 관리란?
상태 관리란 여러 컴포넌트 간의 데이터 전달과 이벤트 통신을 한 곳에서 관리하는 패턴을 의미합니다. 뷰와 성격이 비슷한 프레임워크인 리액트(React)에서는 Redux, Mobx와 같은 상태 관리 라이브러리를 사용하고 있고 뷰에서는 Vuex라는 상태 관리 라이브러리를 사용합니다.
상태 관리(State Management)가 왜 필요한가?
컴포넌트 기반 프레임워크에서는 작은 단위로 쪼개진 여러 개의 컴포넌트로 화면을 구성합니다. 예를 들면, Header, button, List 등의 화면 요소가 각각 컴포넌트로 구성되어 한 화면에서 많은 컴포넌트를 사용합니다. 이에 따라 컴포넌트 간의 통신이나 데이터 전달을 좀 더 유기적으로 관리할 필요성이 생깁니다.
상태 관리로 해결할 수 있는 문제점?
상태 관리는 중대형 규모의 웹 애플리케이션에서 컴포넌트 간에 데이터를 더 효율적으로 전달할 수 있습니다. 일반적으로 앱의 규모가 커지면서 생기는 문제들은 다음과 같습니다.
- 뷰의 컴포넌트 통신 방식인 props,event emit 때문에 중간에 거쳐야할 컴포넌트가 많아지거나
- 이를 피하기 위해 Event Bus를 사용하여 컴포넌트 간 데이터 흐름을 파악하기 어려운 것
이러한 문제점을 해결하기 위해 모든 데이터 통신을 한 곳에서 중앙 집권식으로 관리하는 것이 상태 관리입니다.
상태 관리 패턴
상태 관리 구성요소는 크게 3가지가 있습니다.
- state : 컴포넌트 간에 공유할 data
- view : 데이터가 표현될 template
- actions : 사용자의 입력에 따라 반응할 methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | new Vue({ // state data() { return { counter: 0 }; }, // view template: ` <div>{{ counter }}</div> `, // actions methods: { increment() { this.counter++; } } }); | cs |
위 구성요소는 아래와 같은 흐름으로 동작합니다.
예제 - props를 이용한 컴포넌트간 통신
- App.vue : 상위 컴포넌트 or Parent
- Child.vue : 하위 컴포넌트 or Parent
App.vue
1 2 3 4 5 6 7 8 | <!-- App.vue(Parent) --> <div id="app"> Parent counter : {{ counter }} <br> <button @click="addCounter">+</button> <button @click="subCounter">-</button> <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props로 전달한다. --> <child v-bind:num="counter"></child> </div> | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // App.vue(Parent) import Child from "./Child.vue"; export default { components: { // Child 컴포넌트를 하위 컴포넌트로 등록 child: Child }, data() { return { counter: 0 }; }, methods: { // 이벤트 추가 addCounter() { this.counter++; }, subCounter() { this.counter--; } } }; | cs |
하위 컴포넌트인 Child 컴포넌트를 등록하고 counter를 props 속성으로 내렸습니다.
Child.vue
1 2 3 4 5 6 7 | <!-- Child.vue(Child) --> <div> <hr> Child counter : {{ num }} <br> <button>+</button> <button>-</button> </div> | cs |
1 2 3 4 5 6 | // Child.vue(Child) export default { // 상위 컴포넌트에서 내려준 counter 속성을 num로 받음 props: ["num"] }; | cs |
화면에 표시될 카운터는 Parent 컴포넌트에서 전달받은 props 속성입니다.
정리
이처럼 같은 데이터 속성(counter)을 2개의 컴포넌트에서 접근하여 같은 값을 표현하고 있다는 의미입니다. 이 구조는 뷰의 props 속성을 이용한 기본적인 컴포넌트 통신 방법입니다.
화면의 단위를 잘게 쪼개면 쪼갤수록 한 컴포넌트의 데이터를 다른 컴포넌트의 화면에서 표시할 일이 많아집니다.
만약 컴포넌트의 개수가 무한점 많아진다면, 최상위 컴포넌트에서 최하위 컴포넌트에게 데이터를 전달하기 위해 중간 계층의 컴포넌트에 모두 props, event emit을 선언해주어야 합니다.
이러한 비효율적인 컴포넌트 간 데이터 전달 방식을 Vuex로 해결할 수 있습니다.
예제 - Vuex 를 이용한 컴포넌트간 통신
- store.js : Vuex를 등록할 js 파일
- main.js : store.js를 등록할 main js 파일
store.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | // store.js import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export const store = new Vuex.Store({ // counter라는 state 속성을 추가 state: { counter: 0 } }); | cs |
Vuex와 state 등록합니다. state에 정의된 counter 속성은 'props를 이용한 컴포넌트간 통신'의 counter와 동일한 역할을 합니다. 즉, "state는 컴포넌트 간에 공유할 data 속성을 의미합니다."
main.js
1 2 3 4 5 6 7 8 9 10 11 12 | // main.js import Vue from "vue"; import App from "./App.vue"; // store.js를 불러오는 코드 import { store } from "./store"; new Vue({ el: "#app", // 뷰 인스턴스의 store 속성에 연결 store: store, render: h => h(App) }); | cs |
App.vue
1 2 3 4 5 6 7 8 9 10 | <!-- App.vue(Parent) --> <div id="app"> Parent counter : {{ $store.state.counter }} <br /> <button @click="addCounter">+</button> <button @click="subCounter">-</button> <!-- 기존 코드 --> <!-- <child v-bind:num="counter"></child> --> <child></child> </div> | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // App.vue(Parent) import Child from "./Child.vue"; export default { components: { child: Child }, // 기존 코드 // data () { // return { // counter: 0 // } // }, methods: { addCounter() { this.$store.state.counter++; }, subCounter() { this.$store.state.counter--; } } | cs |
Child.vue
1 2 3 4 5 6 7 | <div> <hr /> Child counter : {{ $store.state.counter }} <br /> <button>+</button> <button>-</button> </div> | cs |
1 2 3 4 | export default { // 기존 코드 // props: ['num'] }; | cs |
store.js에 등록한 state의 counter 속성은 컴포넌트의 템플릿 코드에서 $store.state.counter로 접근할 수 있습니다.
Vuex의 컴포넌트 통신 방식이 props에 의한 통신 방식과의 차이는 아래와 같습니다.
App.vue
- data 속성으로 선언한 counter 값 제거
- Child 컴포넌트로 counter를 props에 의해 전달하지 않음
Child.vue
- parent 컴포넌트에서 props에 의해 데이터를 전달받지 않음
정리
Parent 컴포넌트에서 관리하던 counter 데이터를 Vuex의 state에 넘겨주었고, Child 컴포넌트에서 접근하던 Parent 컴포넌트의 data 속성이 Vuex로 갔기 때문에 이제 Child에서는 Vuex의 state를 바라보면 됩니다. 이제 Parent, Child 컴포넌트 모두 state를 접근할 수 있게 되었습니다. 이외에도 어떤 컴포넌트든 Vuex의 state로 counter를 접근할 수 있습니다.
마무리
이처럼 Vuex를 이용하면 여러 컴포넌트 간에 공유할 데이터를 효율적으로 관리할 수 있습니다. 이외에도 state 값을 쉽게 접근할 수 있는 getters, state 값을 변경하는 mutations, 비동기 처리를 위한 actions, 폴더 구조화 등을 알아야 Vuex로 웹 서비스를 개발할 수 있습니다.
Reference
해당 글은 아래 Reference를 따라 작성하며 공부하였습니다.
https://joshua1988.github.io/web-development/vuejs/vuex-start/
'Framework > Vue.js' 카테고리의 다른 글
[Vue.js] Vue.js 기본 - Vue Template (0) | 2022.07.25 |
---|---|
[Vue.js] Vue.js 기본 - Vue Router, Axios (0) | 2022.07.25 |
[Vue.js] Vue.js 기본 - Component 통신 (1) | 2022.07.24 |
[Vue.js] Vue.js 기본 - Vue, MVVM 패턴, Instance, Component (0) | 2022.07.24 |