Vuex를 다시 일하면서 쓸일이 생겼다..
ㅎㅎ.. 알고는 있지만 정확하게 이해하고 있는거 같진 않아서 다시 정리해보고자 한다!
(백엔드 위주로 하고싶은데.. 참,,, FE 를 놓지 못하게 한다 회사가)
1. Vuex 란?
- Vue의 상태(State) 관리 도구
- 상태: 여러 컴포넌트 간에 공유되는 데이터 속성
- 서비스가 복잡해 졌을 때, 데이터를 다른 컴포넌트에 공유해야 할 수도 있음
- 컴포넌트 레벨이 깊어지거나 관계가 복잡했을 때 상태관리 도구는 유용하게 사용
- 컴포넌트에서 API를 불러와 화면을 그리는 것이 아닌, Vuex에서 API를 불러옴
- Vuex의 State에 API로부터 받아오 데이터를 담음
- State를 컴포넌트에 전달하여 화면을 그림
- Vuex 구성요소
- state : 여러 컴포넌트에 공유되는 data
- getters : 연산된 state 값을 접근하는 속성 computed
- mutations : state 값을 변경하는 이벤트 로직, 메서드 methods
- actions : 비동기 로직을 선언하는 async mehods
2.State
- 여러 컴포넌트 간에 공유할 데이터 - 상태
3.Getter
- state값을 접근하는 속성이자 computed() 처럼 미리 연산된 값을 접근하는 속성
4. Mutations 이란?
- state의 값을 변경 할 수 있는 유일한 방법이자 메서드
- mutations는 commit()으로 동작
// 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
})
- mutations로 상태를 변경해야하는 이유?
- 특정 시점에 어떤 컴포넌트가 state를 접근하여 변경한 건지 확인하기 어렵기 때문
- 따라서, 뷰의 반응성을 거스르지 않게 명시적으로 상태변화를 수행
- 반응성, 디버깅, 테스팅 혜택
src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import {fetchNewsList} from '../api/index.js';
// Vuex는 플러그인 형식으로 제공
Vue.use(Vuex);
// 인스턴스
export const store = new Vuex.Store({
state : {
news: []
},
mutations: {
// 첫번째 인자 state, 두번째 인자 action으로부터 전달받은 값
SET_NEWS(state, news) {
// state에 데이터 전달
state.news = news;
}
},
actions: {
// mutation에 접근할 수 있도록 context 인자가 제공
FETCH_NEWS(context) {
fetchNewsList()
.then(response => {
// mutation에 data를 넘길 수 있음
context.commit('SET_NEWS', response.data);
})
.catch(error => {
console.log(error);
})
}
}
})
src/views/NewsView.vue
<template>
<div>
// store의 state에 접근
<div v-for="item in this.$store.state.news" > {{ item.title }} </div>
</div>
</template>
<script>
export default {
created() {
// action 호출
this.$store.dispatch('FETCH_NEWS');
}
}
</script>
<style>
</style>
5. Actions 이란?
- 비동기 처리 로직을 선언하는 메서드
- 비동기 로직을 담당하는 mutations
- 데이터 요청, Promise, ES6 , async 와 같은 비동기 처리는 모두 actions에 선언
- actions에 비동기 로직을 선언해야하는 이유?
- 언제 어느 컴포넌트에서 해당 state를 호출하고, 변경했는지 규격화를 하여 확인하기 위해
- mutations에 시간차를 두고 state를 변경하는 경우 추적하기 어려움
- 그러므로 mutations속성에는 동기처리 로직만 넣어야함
- Vuex에서 api 호출은 Actions에서 하기
- 비동기 호출
- Backend API를 호출하여 Mutations에 넘겨주기 위한 속성
- Vuex 구조상 actions에서 state에 바로 담을 수 없게 되어 있음
- Actions는 Vue Component에서 Dispatch라는 api로 호출 가능
// store.js
mutations: {
setData(state, fetchData) {
state.product = fetchData;
},
},
actions: {
fetchProductData(context) {
// api 호출 이후 응답을 state에 넣음
return axios.get('https://domaion.com/products/1')
.then(response = context.commit('setData', response));
}
}
// App.vue
methods: {
incrementCounter() {
this.$store.dispatch('fetchProductData');
}
}
6. Module
- state, getters, mutations, actions가 많아질 수록 코드의 가독성은 떨어지고 유지보수는 힘들어짐
- 별도의 파일로 모듈화 하는 것이 편함
- actions.js, mutations.js 파일에 각 코드를 옮기기
7. Helper
7.1 mapStates
- Vuex에 선언한 states 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
<template>
<div>
<div v-for="item in ask"> {{ item.title }} </div>
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
computed: {
// store의 state에 접근하여 ask를 가져옴
// spread 연산자로 computed에 ask를 뿌림
...mapState({
ask: state => state.ask,
}),
},
created() {
this.$store.dispatch('FETCH_ASK');
},
}
</script>
<style>
</style>
7.2 mapGetters
- Vuex에 선언한 getters 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// mix the getters into computed with object spread operator
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
...mapGetters({
// map `this.doneCount` to `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
7.3 mapMutations
- Vuex에 선언한 mutations 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
// App.vue
import { mapMutations } from 'vuex';
methods: {
...mapMutations(['clickBtn']),
atuhLogin() {},
displayTable() {}
}
// store.js
mutations: {
clickBtn(state) {
alert(state.msg);
}
}
<button @click="clickBtn">popup message</button>
7.4 mapActions
- Vuex에 선언한 actions 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
// App.vue
import { mapActions } from 'vuex';
methods: {
...mapActions(['delayClickbtn']),
}
// store.js
actions: {
delayClickBtn(context) {
setTimeout(() => context.commit('clickBtn'), 2000);
}
}
<button @click="delayClickBtn">delay popup message</button>
참고:
https://greedysiru.tistory.com/808
https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper
'DEVELOP > Frontend' 카테고리의 다른 글
[Vue] CodeMirror 사용하기 , Max Length 설정하기 (0) | 2021.11.08 |
---|---|
[Vue] Component Force Rerendering 하기 (강제로 rerender) (2) | 2021.10.26 |
[Vue] computed , watch 중에서 뭐써야하지??? 헷갈리네 (0) | 2020.10.30 |
[Vue] 컴포넌트를 특정부분만 수정해서 쓰고싶다면? Slot ( 컴포넌트 재사용하기) (0) | 2020.06.25 |
React : Functional component 와 Class component의 차이점 (0) | 2020.03.24 |