본문 바로가기
  • 일하면서 배운 내용 끄적이는 블로그
Vue

Vuex로 중앙에서 상태 관리하기

by dhl7799 2024. 5. 7.

Vuex의 정의

Vuex란 Vue.js에서의 상태 관리 라이브러리

Vue.js 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할

React의 Redux같은것

Vuex의 특징

Single Source of Truth

하나의 어플리케이션은 하나의 store만 가진다

하나의 객체가 어플리케이션 전체 state를 포함

단일 상태 트리는 특정 state를 바로 찾을 수 있게 만들고, 현재 앱의 state의 스냅샷을 가져올 수 있어 디버깅 편리

 

State is Reactive

상태가 변경되면 이 상태를 공유하는 다른 곳에서도 상태가 업데이트 됨 

 

State management pattern + Library

Vuex는 상태관리 패턴이자 라이브러리

여러 컴포넌트 간의 데이터 전달과 이벤트 통신을 한곳에서 관리하는 패턴을 Vuex를 통해 구현

상태관리 및 특정 규칙 적용과 관련된 개념을 정의하고 분리해서 코드의 구조와 유지관리 기능 향상

 

주의사항

페이지 새로고침시 store의 데이터 사라짐

-> 쿠키 or 스토리지나 다른 라이브러리 등으로 처리

vuex-persistedstate 라이브러리

모든 store 값들을 localstorage로 저장하면 속도 이슈 발생

공통적으로 사용하는 상태가 아니라면 메모리 낭비

 

Vuex 저장소가 일반 전역 개체와 다른 두가지

1. 반응형

저장소의 상태가 변경되면 업데이트

2. 상태를 직접 변경할 수 없음

commit을 이용해야함(따라서 모든 상태 추적 가능한 기록 남음)

 

예제

 

index.js (store 폴더 안에 생성)

//index.js
import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex);

export default new Vuex.Store({
  state:{
    message: '테스트 입니다'
  },
  mutations: {
    SET_MESSAGE(state, value) {
      state.message = value;
    }
  },
  actions: {
    TIME({commit}, value) {
      return setTimeout(() => {
        commit('SET_MESSAGE', value);
      }, 1000);
    }
  },
  getters: {
  	getMessage: state => state.message
  }
})

 

state

Vue의 data와 같다.

원본 소스의 역할이며 View와 직접적으로 연결되어있는 Model

state는 mutation을 통해서만 변경이 가능하다

mutation을 통해서 state가 변경되면 반응적으로 View가 업데이트 된다.

 

mutations

state를 변경하는 유일한 방법

일반적으로 commit을 통해서만 호출할 수 있음(Helper 함수로 직접 호출 가능)

첫번째 인자는 state 두번째는 payload

 

주로 api를 통해 전달받은 데이터를 mutations에서 가공하여 state를 설정하는데 사용됨

 

actions

비동기 작업이 가능

(그 외에는 mutations와 비슷)

mutations를 호출하기 위한 commit이 가능

action에서 mutations를 호출하여 state를 변경할 수 있음

dispatch를 통해 호출할 수 있음

첫번째 인자는 context, 두번째 인자는 payload

context는 state, commit, dispatch, rootstate 속성들을 포함

주로 axios를 통한 api 호출과 그 결과에 대해 return을 하거나 mutations로 commit하는 용도로 사용

 

getters

예제에는 없지만 Vue의 computed와 같음(계산된 속성)

getter의 결과는 종속성에 따라 캐시되고 변경된 경우에만 다시 계산

state에 대해 연산을 하고 그 결과를 view에 바인딩 할 수 있음

state의 변경 여부에 따라 다시 게산하고 view를 업데이트

 

modules

모듈별(기능 또는 페이지)로 store를 분리하고 관리 가능

실무에서는 단 하나의 store를 사용하기 힘듬

 

설치는 npm install vuex

 

Vue.use(Vuex)로 명시적으로 추가

 

main.js에 store를 추가해준다

//main.js
import Vue from 'vue'
import App from './App.vue'
import store from "./store";
new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

 

vuex에 있는 변수 꺼내오기

<!-- App.vue -->
<template>
  <div id="app">
    {{this.$store.state.message}}
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

 

mutations로 vuex에 저장된 변수 변경하기

<!-- App.vue -->
<template>
  <div id="app">
    <!-- click 하면 setMessage 호출 -->
    <button @click="setMessage">click</button>
    {{this.$store.state.message}}
  </div>
</template>

<script>
export default {
  name: 'app',
  methods: {
    setMessage() {
      //mutations SET_MESSAGE 호출
      this.$store.commit('SET_MESSAGE', '테스트입니다2');
    }
  }
}
</script>

 

action으로 vuex에 저장된 변수 변경하기

<!-- App.vue -->
<template>
  <div id="app">
    <!-- click 하면 setMessage 호출 -->
    <button @click="setMessage">click</button>
    <!-- 2초뒤 message 변경 -->
    {{this.$store.state.message}}
  </div>
</template>

<script>
export default {
  name: 'app',
  methods: {
    setMessage() {
      //actions TIME 호출
      this.$store.dispatch('TIME', '테스트입니다3');
    }
  }
}
</script>

 

map helper

this.$store를 호출하지 않고 vuex를 사용하는 방법

 

store가 다음과 같이 정의되어 있을때

//index.js
import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex);

export default new Vuex.Store({
  state:{
    message1: '',
    message2: ''
  },
  mutations: {
    SET_MESSAGE1(state, value) {
      state.message1 = value;
    },
    SET_MESSAGE2(state, value) {
      state.message2= value;
    }
  },
  actions: {
    //비동기 호출
    MESSAGE({commit}, value) {
      return setTimeout(() => {
        commit('SET_MESSAGE1', value);
      }, 1000);
    }
  },
  getters: {}
})

 

vuex를 사용하는 코드

<!-- App.vue -->
<template>
  <div id="app">
    <button @click="setDispatchTest">dispatch</button>
    <button @click="setCommitTest">commit</button>

    {{this.$store.state.message1}}
    {{this.$store.state.message2}}
  </div>
</template>

<script>
export default {
  name: 'app',
  methods: {
    setDispatchTest() {
      //actions TIME 호출
      this.$store.dispatch('MESSAGE', 'test1');
    },
    setCommitTest() {
      this.$store.commit('SET_MESSAGE2', 'test2');
    }
  }
}
</script>

 

map helper를 사용한 코드

<!-- App.vue -->
<template>
  <div id="app">
    <!-- click 하면 setTest 호출 -->
    <button @click="setDispatchTest">dispatch</button>
    <button @click="setCommitTest">commit</button>
    <!-- state값을 바로 사용할 수 있다 -->
    {{message1}}
    {{message2}}
  </div>
</template>

<script>
//사용할 map helper를 import해준다
import {mapState, mapActions, mapMutations} from 'vuex';

export default {
  name: 'app',
  computed: {
    //사용할 state값을 넣어준다. state는 computed에 넣는 것을 권장
    ...mapState(['message1', 'message2'])
  },
  methods: {
    //사용할 action과 mutation을 선언
    ...mapActions(['MESSAGE']),
    ...mapMutations(['SET_MESSAGE2']),
    setDispatchTest() {
      //action 사용
      this.MESSAGE('메세지1');
      //this.$store.dispatch('MESSAGE', '메세지1');
    },
    setCommitTest() {
      //mutation 사용
      this.SET_MESSAGE2('메세지2');
      //this.$store.commit('SET_MESSAGE2', '메세지2');
    }
  }
}
</script>

 

'Vue' 카테고리의 다른 글

디렉티브(Directives)  (0) 2024.05.08
Router push, replace, go  (0) 2024.05.08
Vue 프로젝트 경로의 @  (0) 2024.05.07
emit으로 자식 -> 부모 데이터 전달  (0) 2024.05.03
Vue 프로젝트 동작 순서  (0) 2024.05.02