[ Vue.js ] Vuex
Vuex란?
무수히 많은 컴포넌트의 데이터를 효율적으로 관리하기 위한 상태관리 패턴이자 라이브러리
▷ React의 Flux패턴에서 기인
▷ Vue.js 중고급 개발자로 성장하기 위한 필수 관문
컴포넌트의 개수가 많아질수록 데이터전달이 어려워지는데
이벤트 버스로 해결한다고 하면?
//Login.vue
eventBus.$emit('fetch', loginInfo);
// List.vue
eventBus.$on('display', data => this.displayOnScreen(data));
// Chart.vue
eventBus.$emit('refreshData',chartData);
어디서 이벤트를 보냈는지, 어디서 받았는지를 알기가 어렵다
컴포넌트 간 데이터 전달이 명시적이지 않다!
Flux - Unidirectional data flow
MVC패턴의 복잡한 데이터 흐름 문제를 해결하는 개발 패턴
Action >> Dispatcher >> Model >> View
모든 데이터 흐름이 한방향(단방향)
프레임워크 자체(패턴)에서 데이터의 흐름을 정형화 시켜서 향후에 발생할 수 있는 문제점들을
미리 예측해서 방지하는 것!
1. action: 화면에서 발생하는 이벤트 도는 사용자의 입력
2. dispatcher : 데이터를 변경하는 방법, 메서드(model을 바꾸기 위한 역할)
3. model : 화면에 표시할 데이터
4. view : 사용자에게 비춰지는 화면
+
MVC 패턴
Controller -- >> Model << -- >> View
양방향으로 이루어진다
기능 추가 및 변경에 따라 생기는 문제점을 예측할 수 없다.
앱이 복잡해지면서 생기는 업데이트루프(ex 페이스북 채팅화면)
Vuex로 해결할 수 있는 문제
1. MVC패턴에서 발생하는 구조적 오류2. 컴포넌트 간 데이터 전달 명시3. 여러개의 컴포넌트에서 같은 데이터를 업데이트 할 때 동기화 문제
Vuex 컨셉
State : 컴포넌트 간에 공유하는 데이터 data( )View : 데이터를 표시하는 화면 templateAction : 사용자의 입력에 따라데이터를 변경하는 methods
view(화면)에서 -> 버튼을 클릭하면(v-on) action을 실행시킨다 -> 데이터를 변경(state)
Vuex 구조
컴포넌트 -> 비동기 로직 -> 동기 로직 -> 상태
Vuex 설치하기( vue3 )
npm install vuex@next --save
강의내용이랑 맞추기 위해 지금부터 vue2로 진행 -> vuex 버전도 vue2에 맞게 설치해야 한다 !
package.json
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14",
"vuex": "^3.6.2"
},
설치된거 확인하고,
src > store > store.js 파일 생성하고 vuex를 등록해주자.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
//use는 Vue의 플러그인 기능 글로벌 functionality를 추가하고싶을때 사용하는것
export const store = new Vuex.Store({
//
});
코어 라이브러리를 등록하고(import)
use는 공식문서에서도 써있는 형태인데, 모든 영역에 특정 기능을 추가하고 싶을때 사용하는 것
이제 main.js에 들고와서 등록을 해준다.
import Vue from 'vue'
import App from './App.vue'
import { store } from './store/store'
new Vue({
store,
render: h => h(App),
}).$mount('#app')
store 라이브러리에 접근하고(import), store변수까지 등록해주면 된다.
Vuex 기술 요소
state : 여러 컴포넌트에 공유되는 데이터 data
getters : 연산된 state 값을 접근하는 속성 computed
mutations : state값을 변경하는 이벤트 로직 메서드 methods
actions : 비동기 처리 로직을 선언하는 메서드 async methods
state
// Vue
data: {
message : 'Hello Vue.js!'
}
// Vuex
state: {
message: 'Hello Vue.js'
}
<!-- Vue -->
<p>{{ message }}</p>
<!-- Vuex -->
<p>{{ this.$store.state.message }}</p>
this.$store > vue use.vuex 전역 플러그인을 추가해주었기 때문에 접근이 가능한거다
getters
//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>
mutations
// store.js
state: {num : 10},
mutations: {
printNumbers(state){
return state.num
},
sumNumbers(state, anotherNum) {
return state.num + anotherNum;
}
}
// App.vue
this.$store.commit('printNumbers');
this.$store.commit('sumNumbers', 20);
mutationas의 commit() 형식 >> 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('modifyState',{
str: 'passed from payload',
num: 20
});
state의 값을 수정할수 있는건 mutations!
state는 왜 직접변경하지 않고 mutations으로 변경할까?
mutations을 거치지 않으면 어느 컴포넌트에서 어떤시점에 해당 state를 변경했는지 추적하기가 어렵다.
>> mutations을 통해 변경하면 vue 개발자 도구에서도 추적할 수 있다.
뷰의 반응성을 거스르지 않게 명시적으로 상태변화를 수행할 수 있다.
actions
// store.js
state: {
num: 10
},
mutations: {
doubleNumber(state){
state.num * 2;
}
},
actions: {
delayDoubleNumber(context){ // context로 store의 메서드와 속성 접근
context.commit('doubleNumber');
}
}
// App.vue
this.$store.dispatch('delayDoubleNumber');
비동기 코드 예제 ( setTimeount() )
// store.js
mutations: {
addCounter(state){
state.counter++
},
},
actions: {
delayedAddCounter(context){
setTimeOut(( => context.commit('addCounter'), 2000);
}
}
//App.vue
methods:{
incrementCounter(){
this.$store.dispatch('delayedAddCounter');
}
}
액션은 디스패치라는 API를 호출해서 액션을 실행시킨다.
왜 비동기 처리 로직은 actions에 선언해야 할까?
언제 어느 컴포넌트에서 해당 state를 호출하고, 변경했는지 확인하기가 어렵다
>> state값의 변화를 추적하기 어렵기 떄문에 mutations속성에는 동기 처리 로직만 넣어야 한다.