본문으로 바로가기

[Vue.js] Vuex 상태 관리 패턴

category Web/Vue.js 2020. 10. 22. 10:58

입사 후 첫 업무로 Vue를 활용한 프로젝트에 투입되었는데

이미 짜여져있는 상태 저장소들의 구조와 흐름을 이해하기 위해

개인적인 학습을 진행하며 정리한 내용입니당.


01. Vuex란?

Vue.js 애플리케이션에 대한 상태 관리 패턴 + 라이브러리

애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를 변경 가능하다.

상태 관리 패턴을 통해 단방향 데이터 흐름의 문제점을 해결 가능하다.

01-1. 단방향 데이터 흐름

flow

단방향 데이터 흐름에는 상태, 뷰, 액션 세가지 개념이 존재한다.

  • 상태는 앱을 작동하는 원본 소스
  • 는 상태의 선언적 매핑
  • 액션은 뷰에서 사용자 입력에 대해 반응적으로 상태를 바꾸는 방법

이러한 데이터의 흐름은 공통의 상태를 공유하는 컴포넌트가 많아지는 경우에 문제를 야기한다.

  • 여러 뷰가 같은 상태에 의존
    • 지나치게 중첩된 컴포넌트를 통과하는 prop이 장황해 짐
  • 서로 다른 뷰의 작업은 동일한 상태를 반영
    • 직접 부모/자식 인스턴스를 참조하거나 이벤트를 통해 상태의 여러 복사본을 변경 및 동기화 해야함
      프로젝트 규모가 커질 수록 복잡해짐

결론적으로 점점 유지보수가 불가능한 코드가 될 수 있다.

 

01-2. Vuex 흐름

Vuex는 단반향 데이터 흐름이 갖는 문제점을 해결하는 방안을 제공한다.

vuex flow

컴포넌트에서 공유된 상태를 추출하고 전역 싱글톤 패턴으로 관리한다.

  • 컴포넌트 트리는 커다란 뷰가 됨
  • 모든 컴포넌트는 트리에 상관없이 상태 접근, 동작 트리거
  • 상태 관리 및 특정 규칙 적용과 관련된 개념을 정의, 분리

결론적으로 코드의 구조와 유지 관리 기능을 향상시킨다.

02. 기본 개념

Vuex는 중심이 되는 Store와 핵심 구성인 State, Mutations, Actions, Getters로 이루어져 있다.

각각 기본적인 개념을 이해하기 위해 정리한 내용은 아래와 같다.

(모듈 구조 파일 작성을 기반으로 설명한다. 모듈형 구조에 대해서는 03 목차에서 설명)

02-1. Store (저장소)

Vuex 애플리케이션의 중심이다. 애플리케이션의 상태를 보유하고있는 컨테이너이다.

 

(1) Vuex store와 일반 전역 개체의 차이점

  Vuex store 전역 개체
반응형 O X
변경 방식 커밋을 이용한 변이 직접

 

저장소의 상태를 직접 변경하지 않고 변이를 수행함으로서 모든 상태에 대한 추적이 가능한 기록이 남게 된다.

코드를 읽을 때 상태 변화 이해에 도움이 된다.

유의할 개념은 아래와 같다.

  • 컴포넌트 안에서 저장소 상태를 사용하는 것 = 단순히 계산된 속성 내에서 상태를 반환하는 것
  • 변경을 트리거하는 것 = 컴포넌트 메소드에서 변경을 커밋하는 것

02-2. State (상태)

프로젝트에서 공통으로 사용할 변수를 정의 하는 부분이다.

프로젝트 내의 모든 곳에서 참조 및 사용이 가능하다.

각 컴포넌트에서 동일한 값을 사용 가능하게 해준다.

 

ex) state.js

export default {
    // 여러 컴포넌트에서 공통으로 사용될 변수가 정의 됨
    items : [],
    ...
}

02-3. Getters

각 컴포넌트의 계싼된 속성(computed)의 공통 사용 정의이다.

여러 컴포넌트에서 동일한 computed가 사용될 경우 Getters에 정의해 공통으로 쉽게 사용할 수 있다.

하위 모듈의 Getters를 불러오기 위해서 this.$store.getters["경로명/함수명"]; 을 사용해야 한다.

 

ex) getters.js

export default {
    items : (state) => state.items,
    ...
}

02-4. Mutation (변이)

state를 변경시키는 역할을 한다. (mutation을 통해서 state변경을 해야만 함)

동기 방식으로 상태 변경을 처리한다.

commit('함수명', '전달인자') 으로 실행시킨다.

mutations 내에 함수 형태로 작성한다.

 

ex) mutations.js

export default {
    // 함수 형태로 작성
    SET_ITEMS (state, data) {
        state.items = {};
        state.items = data;
    },
    ...
}


// 실행 시 아래와 같이 commit
commit('SET_ITEMS', data.list)

02-5. Action (액션)

Mutations을 실행시키는 역할을 한다. (mutation이 실행되면 state도 변경되게 됨)

비동기 방식으로 처리한다.

dispatch('함수명', '전달인자') 으로 실행시킨다.

actions 내에 함수 형태로 작성한다.

 

ex) actions.js

export default {
    // 함수 형태로 작성
    getItemData({ state, commit }, seq) {
        return commit('SET_ITEMS', data.list);
    },
    ...
 }

// 실행 시 아래와 같이
this.$store.dispatch('main/getItemData', ...);

02. 애플리케이션 구조

Vuex 코드 구조에 제한은 없지만 기본적으로 아래와 같은 원칙을 준수한다.

 

03-1. 기본 규칙

  1. 애플리케이션 레벨의 상태는 중앙 집중된 저장소이다.
  2. 상태를 변경시키는 유일반 방법은 동기 트랙잭션인 변이를 커밋하는 것이다.
  3. 비동기식 로직은 캡슐화되어야하며 액션으로 구성된다.

필요에 따라 저장소를 모듈로 나눌 수 있다.

각 모듈은 자체 상태, 변이, 액션, 게터 및 중첩된 모듈을 포함 할 수 있다.

03-2. 코드 구조

모듈을 조합해 쓰는 구조로 작성된다면 프로젝트 구조의 예시는 아래와 같다.

본인 프로젝트 상황에 맞게 구조를 변형할 수 있다.

 

ex) Project Directory

├── index.html
├── main.js
├── api
│   └── ... # API 요청을 위한 추상화를 포함합니다.
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 모듈을 조합하고 저장소를 내보내는 곳 입니다.
    ├── actions.js        # 루트 액션
    ├── mutations.js      # 루트 변이
    └── modules
        ├── cart
        │   ├── index.js         
    	│   ├── actions.js     
    	│   ├── mutations.js     
    	│   ├── getters.js     
    	│   └── state.js   
        └── ...

04. 활용

Vuex 활용 시 유의할 점과 모듈형 구조에서 store에 접근하는 방법에 대한 내용이다.

04-1. rootState 활용

Vuex를 모듈형으로 활용할 때, 기본적으로 state 변수 값은 동일 모듈에 있는 state만 참조하게 된다.

만약 내가 최상위 state 변수나 다른 모듈의 변수 값을 활용하기 위해서는 rootState를 활용해야 한다.

 

하지만 rootState는 actions과 Getters의 인자로만 사용 가능하므로

Mutations에서 사용하기를 원하면 Actions에서 받아서 Mutations 쪽으로 commit해서 활용해야 한다.

04-2. Mutations과 Actions 인자

Mutations Actions
형태 인자 설명 형태 인자 설명
  • mutationsEx1(state, payload){ }
  • mutationsEx2(state, {data1, data2}){ }
  • 기본인자 - state
  • 전달인자 - payload
    • commit으로 넘어옴
    • 객체 형태 가능
  • actionsEx1({rootState, state, dispatch, commit}, payload){ }
  • 기본인자 - {rootState, state, dispatch, commit}
    • 중괄호로 묶어서 받음
  • 전달인자 - payload
    • 객체 형태 가능

04-3. Components에서 각 store 모듈 접근 방법

(1) state

컴포넌트의 computed 내에 작성

  • 기본 접근
  this.$store.state.items
  • mapState 활용
computed: {
    ...mapState({
        items: state => state.items,
    }),

(2) Mutations

컴포넌트의 methods 영역 내에 작성

  • 기본 접근
 this.$store.commit('경로명/함수명')
  • mapMutations 활용
methods: {
    ..mapMutations({
        add: 'item/increment' // this.add()를 this.$store.commit('item/increment')에 매핑
    })
}

 

(3) Actions

컴포넌트의 methods 영역 내에 작성

  • 기본 접근
this.$store.dispatch('경로명/함수명')
  • mapActions 활용
methods: {
    ..mapActions({
        add: 'item/increment' // this.add()를 this.$store.dispatch('item/increment')에 매핑
    })
}

 

(4) Getters

컴포넌트의 computed 내에 작성

  • 기본 접근
this.$store.getters["경로명/함수명"];  
this.$store.getters.doneTodosCount;
  • mapGetters 활용
computed: {
    ...mapGetters ({
        doneCount: 'item/doneTodosCount'
    }),

참고: 공식문서 - vuex.vuejs.org/kr/

 

Vuex가 무엇인가요? | Vuex

Vuex가 무엇인가요? Vuex는 Vue.js 애플리케이션에 대한 상태 관리 패턴 + 라이브러리 입니다. 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를

vuex.vuejs.org