-
[Vue.js] Vuex - (1) Vuex 기본Front-End(Web)/Vue 2021. 6. 10. 01:28반응형
드디어, Vuex 라고 하는 Vue.js의 상태관리 라이브러리를 학습하는 단계에 돌입했다!
다행인 점은, Context나 Redux를 사용해 보았기에 Vuex를 처음 접하는데 위화감은 덜 할 것 같다.
심지어, Redux의 Flux 패턴과 어느 정도 유사하면서도, 좀 더 간소화된 절차를 가진다는 것으로 선임 개발자님께 대략적으로 들었다.
Redux와는 또 다른, Vuex만의 특징과 장점은 어느 것이 있을지 한 번 학습하면서 정리해보겠다! (분량이 길 시 포스팅 분리하겠다.)
* 이 글은 캡틴판교님의 Vue.js 강의 및 블로그를 기반으로 학습한 내용을 정리하고 있습니다.
💚 Vuex 란?
공식문서에서는, Vue.js 애플리케이션의 복잡한 컴포넌트들을 관리하는 상태관리 패턴 + 라이브러리로 정의한다.
컴포넌트들에 대한 중앙 집중식 저장소 역할을 하며, 예측 가능한 방식으로 상태를 변경할 수 있다.
React의 Redux 등과 같은 Flux 패턴을 차용하여 데이터를 관리하며, Vue devtools 와도 통합되어 디버깅이 가능하다.
- 배경
특정 앱의 기능은 다음 요소들로 이루어진다. 이 세 가지 요소가 기본적으로 순환되는 것이 "단방향 데이터 흐름" 이다.
- 데이터이자 소스인 상태
- 표시하는 선언적 매핑인 뷰
- 반응적으로 상태를 바꾸는 액션
하지만, 이 상태가 공통요소이고 여러 컴포넌트가 공유할 경우 단순함이 저하되며, 아래와 같은 문제에 봉착한다.
- 여러 뷰는 같은 상태에 의존한다. => 뎁스가 깊은 자식 컴포넌트는 많은 props가 소요되며, 형제 컴포넌트 적용이 번거로움
- 서로 다른 뷰의 작업은 동일한 상태에 적용되야 한다. => 부모로 끌어올리던가, 이벤트 버스로 복사본을 전파하는 추가소요가 생김
이러한 문제점들로 인한 위험성과 유지보수의 불리함을 개선하기 위해, 공통상태를 전역 싱글톤을 관리하는 Vuex가 등장한 것이다.
- Vuex 컨셉 및 구조
위에서 언급했듯이, Vue는 Flux 패턴 기반의 단방향 데이터 컨트롤이다. 다만, React와 용어 및 원리가 일부 다르다.
* MVC는 Model 기반의 양방향 데이터 컨트롤, Flux 패턴은 Store 기반의 단방향 데이터 컨트롤이다. 자세한 내용은 첨부 참조바란다!
( 참조링크 : https://beomy.tistory.com/44 )
전반적인 과정은, 컴포넌트에서의 디스패칭을 시작으로 Actions(비동기), 이를 통한 Mutations(동기) 호출이 State를 갱신한다.
💚 Vuex 사용법
- 설치
// CDN <script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script> // NPM or Yarn npm install vuex --save yarn add vuex
- 초기설정
Redux와 유사하게, store > store.js 경로를 만들어서 여기에 환경을 구축한다.
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { // ... }, mutations: { // ... }, });
use()는 Vue를 사용하는 모든 영역에 글로벌하게 기능을 추가하는 문법이다. Vuex와 같은 기능을 "플러그인" 이라고 명명한다.
이러한 플러그인들에는 메서드($method)가 지원되며, 이를 전역에서 사용 가능하다. (예시 : Vuex 의 this.$store 등 ..)
이제, main.js 혹은 필요한 Vue 컴포넌트의 인스턴스에 store 필드를 설정해주기만 하면 된다.
// main.js new Vue({ el: "#app", store, render: h => h(App), });
1) Store(저장소)
Store는 기본적으로 앱의 전역상태를 보유하는 컨테이너이다. Vuex Store는 일반 전역개체와 크게 2가지 다른 점이 존재한다.
- Store는 반응형이다. Vue 컴포넌트는 상태를 검색할 때, Store의 상태가 변경되면 효율적으로 대응한다.
- Store 상태를 직접 변경할 수 없다. 명시적인 "commit" 요청을 통한 갱신만 가능하다. (안전성, 기록추적 등의 장점)
- 기술요소
2) State(상태)
여러 컴포넌트 간에 공유되는 데이터(상태)이다. Vuex는 단일 객체가 모든 애플리케이션의 상태를 포함하고 있다.
// Vue data: { msg: 'hello', }; // Vuex state: { msg: 'hello', }; // Vue <p>{{ msg }}</p> // Vuex <p>{{ this.$store.state.msg }}</p>
3) getters
state 값을 접근하는 속성이자 computed() 처럼 상태값의 연산에 관한 속성이다. Store 상태값에 기인한 계산이 있을때 유용하다.
// 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>
4) mutations(변이)
state 값을 변경하는 유일한 방법이자 메서드이다. mutation 메서드는 첫 번째 인자가 state, 두 번째 인자부터는 arguments 다.
commit() 키워드로 작동시키며, commit의 첫 번째 인자로 "mutations 메서드명", 두 번째 인자부터는 arguments를 입력한다.
// store.js state: { num: 10 }, mutations: { printNums(state) { return state.num }, sumNums(state, value) { return state.num + value } }, // App.vue this.$store.commit('printNums'); // 10 this.$store.commit('sumNums', 20); // 30
React와 비교하면, mutations의 메서드명은 action, 메서드들은 reducer와 유사하다.
그렇기에, 메서드명도 action처럼 상수화하여, Vuex의 동작들을 types 파일에 집약하면서도 linter 효율성을 극대화시킬 수 있다.
// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // ES2015에서 계산 된 프로퍼티 이름 기능을 사용하여 // 상수를 함수 이름으로 사용할 수 있습니다 [SOME_MUTATION] (state) { // 변이 상태 } } })
* payload 를 가진 commit
payload에 객체 형태로 많은 데이터를 첨부한다. (payload 외에 다른 변수명을 사용해도 되나 일반적으로 통용되는 변수명임)
// store.js state: { num: 10 }, mutations: { modify(st, payload) { console.log(payload.str); return st.num += payload.num } } // App.vue this.$store.commit('modify', { str: 'passed from App.vue', num: 20, });
* 객체 스타일 commit
좀 더 개선된 방법으로, commit의 첫 번째 인자인 mutations 메서드명을 객체의 type 필드로 대입할 수 있다.
// 개선 전 this.$store.commit('modify', { str: 'passed from App.vue', num: 20, }); // 개선 후 this.$store.commit({ type: 'modify', // 메서드명 str: 'passed from App.vue', num: 20, });
5) actions
비동기 처리로직을 선언하는 메서드(mutations). 데이터 요청, Promise 등 비동기 처리는 actions에 선언한다.
actions의 메서드들은 상태를 갱신하는게 아니라 mutations의 상태관련 로직들을 비동기로 실행한다.
그래서 context를 인자로 받으며, 이를 통해 mutations 메서들들에 접근해서 commit 할 수 있다.
dispatch() 키워드로 동작시키며, commit(mutations)과 마찬가지로 actions의 메서드명을 첫 번째 인자로 입력한다.
// store.js state: { num: 10, }, mutations: { doubleNum(state) { state.num * 2; } }, actions: { delayDoubleNum(context) { context.commit('doubleNum'); } } // App.vue this.$store.dispatch('delayDoubleNum');
* actions 비동기 코드 예제
// 1) Timer mutations: { addCounter(state) { state.count += 1; }, }, actions: { delayedCount(context) { setTimeout(() => context.commit('addCounter'), 2000); }, };
// 2) Server Request(axios) mutations: { setData(state, data) { state.list = data; }, }, actions: { fetchData(context) { return axios.get('https://domain.com/products) .then(res => context.commit('setData, res); }, };
Vuex를 처음 접하면서, Redux와는 또 사뭇 다른 부분이 정말 많았다.
우선, 비동기 로직을 actions로 별도로 분리하는 것이, 서드파티를 연결해야하는 Redux에 비해 좀 더 정형적이어서 맘에 들었다.
또한, state, getters, mutations(동기로직), actions(비동기로직) 이 각각 관리되는 점이 셋팅하는데 있어 번거로움은 존재하나, 유지보수에는 확실히 이점이 있을 거라고 생각됬다.
Vuex도 React-redux의 useSelector, useDispatch 훅들과 같이 store를 좀 더 용이하게 사용하는 내장함수가 존재한다고 한다.
이를, Helper 함수라고 명명한다. 이 부분에 대해서는 다음 포스팅에서 정리해보겠다!
[출처]
- Vuex 공식문서(번역본) : https://vuex.vuejs.org/kr/
- Vuex 캡틴판교 님의 블로그 : https://joshua1988.github.io/web-development/vuejs/vuex-start/
반응형'Front-End(Web) > Vue' 카테고리의 다른 글
[Vue.js] Vuex - (3) Store 모듈화 (0) 2021.06.13 [Vue.js] Vuex - (2) Helper 함수 (0) 2021.06.11 [Vue.js] Template 문법 (0) 2021.06.03 [Vue.js] Vue Router (0) 2021.06.02 [Vue.js] 컴포넌트(Component), Props & Event (0) 2021.05.26