[Vue] 중앙상태관리와 Vuex

작성:    

업데이트:

카테고리:

태그: ,

Vuex

Vuex란?

  • vue.js의 Statement management pattern(상태관리패턴) + Library
  • state를 전역 저장소로 관리할 수 있도록 지원하는 라이브러리
  • 상태가 예측 가능한 방식으로만 변경될 수 있도록 보장하는 규칙 설정
  • 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할
  • Vue의 공식 devtools와 통합되어 기타 고급 기능 제공


State

  • data이자 해당 애플리케이션의 핵심이 되는 요소
  • 중앙에서 관리하는 모든 상태 정보


상태 관리 패턴

  • 컴포넌트의 공유된 상태를 추출하고 이를 전역에서 관리
  • 상태 관리 및 특정 규칙 적용과 관련된 개념을 정의하고 분리 → 코드의 구조와 유지 관리 기능 향상
  • 컴포넌트는 커다란 view가 되며, 모든 컴포넌트는 트리에 상관없이 상태에 엑세스하거나 동작을 트리거할 수 있음
  • ※ 트리거 : 특정한 동작에 반응해 자동으로 필요한 동작을 실행하는 것


(Origin) 기존 Pass props & Emit event

  • 각 컴포넌트는 독립적으로 데이터를 관리
  • 데이터는 단방향 흐름으로 부모자식 간의 전달만 가능
  • 반대의 경우 이벤트를 트리거


장점

  • 데이터의 흐름을 직관적으로 파악 가능


단점

  • 컴포넌트 중첩이 깊어지는 경우 동위 관계의 컴포넌트로의 데이터 전달이 불편해짐
  • 공통의 상태를 공유하는 여러 컴포넌트가 있는 경우 데이터 전달 구조가 매우 복잡
  • ex. 지나치게 중첩된 컴포넌트를 통과하는 prop


단방향 데이터 흐름

  • state : 앱을 작동하는 원본 소스(data)
  • view : state의 선언적 매핑(화면)
  • action : view에서 사용자 입력에 대해 반응적으로 state를 바꾸는 방법(methods)


(New) Vuex management pattern

  • 중앙 저장소(store)에 state를 모아놓고 관리
  • 규모가 큰 (컴포넌트 중첩이 깊은) 프로젝트에서 매우 효율적
  • 각 컴포넌트에서는 중앙 집중 저장소의 state만 신경쓰면 됨
  • 동일한 state를 공유하는 다른 컴포넌트들도 동기화


state 관리 A : 단방향 흐름에 의존

A-1. 규모가 작은 경우 : 문제가 없다.

  • 부모자식 간 컴포넌트 관계가 단순 또는 depth가 깊지 않은 경우
  • 데이터를 쉽게 이동, 직관적으로 데이터 흐름 파악 가능


A-2. 규모가 큰 경우 : 어렵다.

  • 상태를 공유하는 컴포넌트의 상태 동기화 관리가 어려움
  • 상태를 전달할 때 상 → 하 로만 가능


A-3. 동기화 방식

  • A 컴포넌트의 상태를 공유하는 다른 컴포넌트에 pass props & emit event 를 통해 동기화


state 관리 B : Vuex 활용

B-1. 등장

  • 상태 변화에 따른 여러 흐름을 모두 관리해야 하는 불편 해소
  • 상태는 데이터를 주고받는 컴포넌트 사이의 관계도 충분히 고려해야 함
  • 때문에 상태 흐름 관리 매우 중요


B-2. 의의

  • 상태를 올바르게 관리하는 저장소의 필요성
  • 상태를 한 곳(store)에 모두 모아 놓고 관리
  • 상태의 변화는 모든 컴포넌트에서 공유
  • 상태의 변화는 Vuex가 관리, 해당 상태를 공유하고 있는 모든 컴포넌트는 변화에 ‘반응’


B-3. 동기화 방식

  • B 컴포넌트와 같은 상태를 공유하는 다른 컴포넌트는 신경쓰지 않고, 오로지 상태의 변화를 Vuex에 알림


Vuex Core Concepts

State

  • 중앙에서 관리하는 모든 상태 정보(data)
  • Vuex는 single state tree 사용
  • 즉, 이 단일 객체는 모든 애플리케이션 상태를 포함하는 원본소스(single source of truth)의 역할을 함
  • 이는 각 애플리케이션마다 하나의 저장소만 갖게 된다는 것을 의미

  • 여러 컴포넌트 내부에 있는 특정 state를 중앙에서 관리
  • Vuex Store에서 각 컴포넌트에서 사용하는 state를 한눈에 파악 가능
  • state가 변화하면 해당 state를 공유하는 여러 컴포넌트의 DOM은 (알아서) 렌더링
  • 각 컴포넌트는 Vuex Store에서 state 정보를 가져와 사용


Mutation

  • 실제로 state를 변경하는 유일한 방법
  • mutation의 handler(핸들러 함수)는 반드시 동기적이어야 함
  • 비동기적 로직(ex. 콜백함수)은 state가 변화하는 시점이 의도한 것과 달라질 수 있다.
  • 또한 콜백이 실제로 호출될 시기를 알 수 있는 방법이 없다. (추적 불가)

  • 첫 번째 인자로 항상 state를 받음
  • Actions에서 commit() 메서드에 의해 호출


Actions

  • Mutations와 유사하지만 차이점이 있음
  1. state를 변경하는 대신 mutations를 commit() 메서드로 호출해서 실행
  2. mutations와 달리 비동기 작업 포함 가능(BE API와 통신해 Data Fetching 등의 작업 수행)
  • context 인자 받음
  • context 객체를 통해 store/index.js 파일 내에 있는 모든 요소의 속성 접근 & 메서드 호출 가능
  • 단, state를 직접 변경하지 않음(가능하지만 금지)
  • 컴포넌트에서 dispatch() 메서드에 의해 호출

  • ⭐ 결론 : Actions를 통해 state 조작 자체는 가능하지만 오로지 Mutation을 통해서만 조작!!
  • 명확한 역할 분담을 통해 서비스 규모가 커져도 state를 올바르게 관리


Getters

  • state를 변경하지 않고 활용하여 계산을 수행
  • computed 속성과 유사
  • 저장소의 state를 기준으로 계산
  • state 종속성에 따라 캐시(cached)되고, 종속성이 변경된 경우에만 재계산


Component Binding Helper

  • JS Array Helper Method를 통해 배열 조작을 편하게 하는 것과 유사
  • 논리적인 코드 자체가 변하는 것이 아니라 쉽게 사용할 수 있도록 하기 위함
  • mapState, mapGetters, mapActions, mapMutations


mapState

  • computed와 Store의 state를 매핑
// vuex 모듈에서 mapState 메서드만 가져옴
import { mapState } from 'vuex'
// store.state의 object를 computed 함수에 지정하는 방식
computed: {
  todos: function () {
    return this.$store.state.todos
  },
}

// computed 이름이 state 이름과 같을 때 문자열 배열 전달
computed: mapState(['todos'])

// object spread operator
computed: {
  ...mapState(['todos'])
}


mapActions

  • actions을 전달하는 컴포넌트 method 옵션 생성
  • 주의📢 actions로 전달하는 데이터가 있는 경우
    • dispatch는 payload로 데이터를 넘겨줌
    • mapActions는 pass prop으로 변경해서 전달
    • 콜백함수 지정에 (data)로 호출 시 보내는 데이터를 미리 지정하는 Vue의 특수 문법


vuex-persistedstate

  • Vuex state를 자동으로 브라우저의 LoaclStorage에 저장하는 라이브러리
  • 페이지가 새로고침 되어도 Vuex state를 유지
$ npm i vuex-persistedstate


// index.js
import createPersistedState from 'vuex-persistedstate'

export default new Vuex.Store({
  plugins: [
    createdPersistedState(),
  ],
})

댓글남기기