React에서는 Flux 패턴과 같은 상태 관리 아키텍처가 존재합니다.
Vue또한 상태 관리를 하기 위해 무엇인가 존재할 것 같은데요.
그렇게 찾아보다가 Vuex를 찾게 되었습니다!
Vuex가 무엇이고 어떤 특징을 가지는 지 알아봅시다.
1. Vuex
Vuex는 Vue.js 애플리케이션을 위한 상태 관리 라이브러리로, 중앙 집중식 저장소를 제공하여 컴포넌트 간의 상태 관리를 용이하게 합니다!
이는 애플리케이션의 상태를 예측 가능한 방식으로 관리하고, 상태 변경을 추적하고, 디버깅을 쉽게 할 수 있게 해줘요.
이는 React의 Flux 패턴에서 기인했다고 합니다.
※ Flux 패턴
Flux 패턴이 뭘까요?
Flux 패턴이란, Facebook에서 제안한 애플리케이션 아키텍처로 MVC 패턴의 복잡한 데이터 흐름 문제를 해결하는 개발 배턴입니다.(Undirectional data flow)
구조는 다음과 같아요.
- action : 화면에서 발생하는 이벤트 or 사용자의 입력
- dispatcher : 데이터를 변경하는 방법, 메서드
- model : 화면에 표시할 데이터
- view : 사용자에게 비춰지는 화면
Flux 패턴은 단방향 데이터 흐름입니다.
즉, 데이터의 흐름이 여러 갈래로 나뉘지 않고 단방향으로만 처리돼요.
경로는 다음과 같습니다.
- View에서 사용자 상호작용이 발생하면, Action이 생성됩니다.
- Action이 Dispatcher를 통해 Store로 전달됩니다.
- Store는 Action을 처리하고 상태를 변경합니다.
- 상태 변경 이벤트가 발생하여, View가 다시 렌더링됩니다.
Vue.js 또한, 복잡한 애플리케이션에서 컴포넌트의 개수가 많아지면 컴포넌트 간에 데이터 전달이 어려워집니다.
이벤트 버스로 해결하고자 해도 어디서 이벤트를 보냈는지 or 어디서 이벤트를 받았는지 알기 어려워요..
그러기에 사용하는 것이 Vuex입니다.
2. Vuex의 컨셉
Vuex의 간단한 컨셉은 다음과 같습니다.
- State : 컴포넌트 간에 공유하는 데이터 (data( ))
- View : 데이터를 표시하는 화면 (template)
- Action : 사용자의 입력에 따라 데이터를 변경하는 (methods)
3. Vuex의 구조
Vuex의 구조는 다음과 같습니다.
컴포넌트 → 비동기 로직 → 동기 로직 → 상태
4. Vuex 설치하기
Vuex를 설치하기 위해서는 다음과 같이, 입력해 줍시다.
npm install vuex@3.6.2 --save
그 다음, src 폴더 안에 store 폴더 만들고, 그 안에 store.js 파일을 만든 후, 다음과 같이 입력해 줍시다.
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
//
});
입력했으면, main.js 파일을 다음과 같이 수정해 줍시다.
main.js
import Vue from "vue";
import App from "./App.vue";
import { store } from "./store/store";
Vue.config.productionTip = false;
new Vue({
el: "#app",
store,
render: (h) => h(App),
})
이렇게 하면 설치 및 등록이 완료되었어요!
5. Vuex의 주요 개념
1) State(상태)
애플리케이션의 상태를 저장하는 객체입니다. (data)
컴포넌트 데이터 속성과 유사하지만, 중앙 집중식으로 관리됩니다.
사용 방법은 다음과 같아요.
// Vue
data : {
message: "Hello Vue.js!"
}
// Vuex
state: {
message: "Hello Vue.js!"
}
<!-- Vue -->
<p>{{ message }}</p>
<!-- Vuex -->
<p>{{ this.$store.state.message }}</p>
2) Getters(게터)
Vuex의 state를 계산하여, 반환하는 함수입니다. (computed)
컴포넌트에서 state를 가져오는 방법을 정의할 수 있습니다.
사용방법은 다음과 같아요.
// store.js
state: {
num: 10
},
getters: {
getNumber(state) {
return state.num;
},
doubleNumber(state) {
return state.num * 2;
}
}
<p>{{ this.$store.getters.getNumber }}</p>
<p>{{ this.$store.getters.doubleNumber }}</p>
3) Mutations(뮤테이션)
state를 변경하는 이벤트 로직 or 메서드입니다. (methods)
상태 변경은 항상 뮤테이션을 통해서만 이루어져야 해요.
뮤테이션은 commit( )으로 동작시킵니다.
사용방법은 다음과 같아요.
// store.js
state: { num: 10 },
mutations: {
printNumbers(state) {
return state.num
},
sumNumbers(state, anotherNum) {
return state.num + anthorNum;
}
}
// App.vue
this.$store.commit('printNumbers');
this.$store.commit('sumNumber', 20);
state를 변경하기 위해 mutations를 동작시킬 때, 인자(payload)를 전달할 수 있습니다.
// store.js
state: { storeNum: 10 },
mutations: {
modifyState(state, payload) {
console.log(payload.str);
return state.storeNum += payload.num;
}
}
// App.vue
this.$store.commit('modyfyState', {
str: 'passed from payload',
num: 20,
});
※ state에서 직접 변경하지 않고 mutations로 변경하는 이유
state에서 직접 변경하면 편한데, 왜 mutations를 거쳐서 변경하는 걸까요?
그 이유는 여러 개의 컴포넌트에서 state 값을 변경하는 경우, 어느 컴포넌트에서 해당 state를 변경했는지 추적하기가 어렵기 때문입니다.
특정 시점에 어떤 컴포넌트가 state를 접근하여, 변경한 것인지 확인하기 어렵기에 따라서, 뷰의 반응성을 거스르지 않게 명시적으로 상태 변화를 수행하는 것입니다.
4) Actions(액션)
비동기 작업을 수행하고, 뮤테이션을 커밋하여 상태를 변경하는 메서드입니다. (aysnc methods)
API 호출 같은 비동기 작업을 수행한 후, 상태 변경을 트리거할 때 사용됩니다.
데이터 요청, Promise, ES6 async과 같은 비동기 처리는 모두 actions에 선언합니다.
사용방법은 다음과 같아요.
// 예제 1
// store.js
mutations: { // 동작 순서 3
addCounter(state) {
state.counter;
}
},
actions: {
delayAddNumber(context) { // context로 store의 메서드와 속성 접근 (동작 순서 2)
setTimeout(() => context.commit('addCounter'), 2000);
}
}
// App.vue
methods: {
incrementCounter() {
this.$store.dispatch('delayAddNumber'); // 동작 순서 1
// 예제 2
// store.js
mutations: {
setData(state, fetchedData) {
state.product = fetchedData;
}
},
actions: {
fetchProductData(context) {
return axios.get('https://domain.com/products/1')
.then(response => context.commit('setData', response));
}
}
// App.vue
methods: {
getProduct() {
this.$store.dispatch('fetchProductData');
}
}
※ 비동기 처리 로직을 actions에 선언하는 이유
왜 비동기 처리 로직은 mutations에 넣지 않고 actions에 처리해야 할까요?
그 이유는 다음 그림과 같습니다.
그림처럼 여러 개의 컴포넌트에서 mutations로 시간 차를 두고 state를 변경하는 경우, 언제 어느 컴포넌트에서 해당 state를 호출하고, 변경했는지 확인하기가 어려워요.
즉, state 값의 변화를 추적하기 어렵기 때문에 mutations 속성에는 동기 처리 로직만 넣어야 해요.
6. 정리하며
지금까지 Vuex에 대해 알아보았습니다.
Vuex는 대규모 애플리케이션에서 컴포넌트 간의 상태 공유를 쉽게 하고, 상태 관리 로직을 깔끔하게 유지할 수 있도록 돕는다고 합니다.
이를 활용하면, Vue.js를 더욱 쉽고 편하게 개발할 수 있을 것 같아요!
참고
'Front-End Study > Vue.js' 카테고리의 다른 글
AG Grid (3) | 2024.07.22 |
---|---|
Helper 함수 (0) | 2024.07.09 |
Vue.js에서의 ES6 (0) | 2024.07.08 |
Computed vs Watch (0) | 2024.07.04 |
Props와 Events (0) | 2024.07.04 |