3 minute read


1. Vuex

Vuex란 React의 Flux 패턴에서 기인한 Vue.js의 상태관리 라이브러리로 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 하며 의도적인 방법으로 상태를 관리할 수 있다. 복잡한 애플리케이션에서 컴포넌트의 개수가 많아지면 컴포넌트 간의 데이터 전달이 어려워진다. props나 이번트 버스로 처리할 수 있지만 컴포넌트 간의 데이터 전달이 명시적이지 않기 때문에 Vuex를 사용한다.

그렇다면 Vuex에서 말하는 상태는 무엇일까? 또 상태관리는 무엇일까?

Vuex에서 말하는 상태란 쉽게 얘기해서 Vue의 data 속성이다. 컴포넌트 간 공유할 수 있는 데이터인 data 속성을 ‘상태’라고 하며 Vuex에서는 어떻게 상태관리를 하고 있는지 알아보자.

앞서 말한 것과 같이 Vuex는 React의 Flux 패턴을 사용하고 있는데 Flux 패턴은 MVC 패턴의 복잡한 데이터 흐름 문제를 해결하기 위해 개발된 패턴이다.

MVC 패턴은 뷰와 보델이 양방향 통신이 가능해서 하나의 뷰가 모듈을 변경했을 때, 그 모듈과 연관된 뷰들을 갱신하고 업데이트된 뷰들이 또 연관된 모델을 갱신하고 하는 과정이 반복되며 서로 엮여있는 관계를 추적하기 힘들다는 단점이 있다.
하지만 Flux 패턴은 아래 구조와 같이 Vue와 동일하게 단방향 데이터 흐름을 갖는다. 따라서 양방향으로 데이터를 주고 받을때보다 쉽게 예측이 가능하다.



1.1 Action

화면에서 발생하는 이벤트 또는 입력을 의미한다.

1.2 Dispatcher

Dispatcher는 Store가 등록해 놓은 callback 함수들이 존재하고, Action을 감지하면 Store의 callback 함수를 실행시킨다. Store의 데이터를 조작하는 것은 Dispatcher를 통해서만 가능하고 callback 함수를 순차적으로 처리하도록 관리하는 역할을 한다.

1.3 Store

Store는 Vuex 애플리케이션의 상태를 보유하고 있는 컨테이너로 상태를 변경할 수 있는 메서드를 가지고 있다. 발생한 Action의 타입에 따라 그에 맞는 데이터를 변경하는 callback 함수를 Dispatcher에 등록하고 Dispatcher에서 callback 함수를 실행하여 상태가 변경되는 뷰(View)에게 데이터 변경을 알리는 역할을 한다.
또한, Store는 메모리에 저장되는 것으로 새로고침 시 초기화 되고 세션이나 쿠키 처럼 브라우저가 닫힐 때까지 유지되지 않는다.

1.4 View

View는 컴포넌트라고 생각하면 쉽다. Store에서 데이터 변경을 알리면 View에서는 데이터를 가져와 렌더링한다.



2. Vuex의 구조

Flux 패턴에 기인한 Vuex의 전체적인 흐름도를 보면 아래와 같다. 얼핏보면 헷갈려 보이지만 위에서 설명한 Flux구조의 Action과 Vuex의 Actions는 다른 것이다.

Flux의 Action은 말 그대로 사용자의 행위를 말하는 것이고 Vuex의 Acitions는 로직상의 행위를 말하는 것이므로 혹시나 헷갈리는 일이 없도록 하자.



위의 이미지를 기반으로 간단하게 예를 들어보자.

2.1 Vuex의 프로세스

해커스라는 웹 사이트에서 제공하는 api를 사용해서 데이터를 가져오는 예제이다.

2.1.1 Vue Components (views/NewsView.vue)

created()가 호출면서 내부에 있는 코드를 실행하는데 dispatch를 사용해서 action의 FETCH_NEWS를 실행시킨다.(Actions는 dispatch로 호출할 수 있다.)

template 내부 코드는 html로 화면을 구성하는 부분으로 프로세스가 완료되고 나면 최종적으로 결과과 화면에 보여지게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
	<div>
		<p v-for="item in this.$store.state.news">
			<a v-bind:href="item.url">{{ item.title }}</a>
		</p>
  </div>
</template>

<script>

export default {
	created(){
		this.$store.dispatch('FETCH_NEWS');
	}
}
</script>

<style></style>

2.1.2 Actions (store/actions.js)

dispatch를 통해 actions의 FETCH_NEWSF를 호출하면 내부의 fetchNewsList 함수를 실행하는데 해당 함수는 api/index.js에 위치한다.(아래 2.1.3 Backend API 확인)
통신 이후 데이터를 받아오면 응답 값을 response로 받고 context의 commit 속성을 사용해서 Mutations을 실행한다.

아래 코드는 ES6의 {} 문법을 사용해서 context의 commit을 직접 꺼내서 호출한 것이다. 이와 같이 사용하면 코드를 한결 쉽게 작성할 수 있으므로 두 개의 코드를 비교하면서 차이를 알아두도록 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { fetchNewsList } from '../api/index.js';
//ES5
FETCH_NEWS(context){
	fetchNewsList()
		.then(response => {
			context.commit('SET_NEWS', response.data);
		})
		.catch(error => {
			console.log(error);
		})
},

//ES6
FETCH_NEWS({commit}){	//context의 commit을 직접 사용하도록
	fetchNewsList()
		//마찬가지로 response에서 data를 바로 사용하도록 처리
		.then(({data}) => {
			//context 없이 바로 commit 사용 가능
			commit('SET_NEWS', data);
		})
		.catch(error => {
			console.log(error);
		})
},

2.1.3 Backend API (api/index.js)

사용자에 의한 이벤트가 발생(api 호출)하고 axios를 사용해서 데이터를 가져온다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import axios from 'axios';

const config = {
    baseUrl : 'https://api.hnpwa.com/v0/'
}

function fetchNewsList() {
    return axios.get(`${config.baseUrl}news/1.json`);
}

export{
    fetchNewsList,
}

2.1.4 Mutations

Mutations는 State를 바꾸는 유일한 수단으로 함수로 구현된다. state를 받을 수 있고 두 번째 인자로 payload(data)를 받을 수 있다. 두 번째인자로 actions에서 넘겨준 데이터를 받고 state의 상태를 변경해준다.

1
2
3
4
5
export default{
    SET_NEWS(state, data){
        state.news = data;
    },
}

2.1.5 State

Mutations에서 변경한 state가 선언된 부분이다.

store 내부에 선언되어 있는 state.news는 비어 있는 상태지만 Mutations에서 state.news = data를 통해 데이터를 넣어줬기 때문에 news는 최초 api 통신 부분에서 가져온 데이터가 들어오게 된다.

state의 news에 데이가 들어오고 state가 변경됨에 따라 Vue Component의 template의 html 코드가 호출되며 화면에 반영된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue';
import Vuex from 'vuex';

import mutations from './mutations.js'
import actions from './actions.js'

Vue.use(Vuex);

export const store = new Vuex.Store({
    state : {
        news : [],
    },
    mutations : mutations,
    actions : actions
});