Vuex 개념
Vuex는 왜 필요한가?
Vue에서 사용할 데이터는 data 옵션에 정의해준다. 그리고 선언한 data를 props를 사용해 하위 컴포넌트에 전달할해준다. 여기서 문제가 생긴다. 만약 선언한 data를 상위 컴포넌트에서 사용할 경우에는 data를 전달해줄 방법이 없다. 또한 어떤 컴포넌트의 하위 컴포넌트의 하위 컴포넌트가 선언한 data를 필요로할때 이 값을 전달하기 위해서는 해당 값을 필요로 하지 않는 컴포넌트도 props를 전달하기위해 선언해주어야한다는 번거로움이 있다. 이렇게 컴포넌트 내부에서 데이터를 선언해 사용하면 다른 컴포넌트에서 접근이 쉽지 않다. 이를 해결하기 위해 전역 데이터 저장소인 vuex를 사용한다.
Vuex란 무엇인가?
위에서 vuex는 전역 데이터 저장소라고 하였다. 즉 데이터를 컴포넌트 내부에서 저장하는 것이 아닌 store라는 공간에 전역적(global)으로 데이터를 저장해 모든 컴포넌트가 쉽게 접근할 수 있도록 하는 구조를 가졌다.
Vuex 사용하기
Vuex 설치
npm
npm install vuex
yarn
yarn add vuex
Vuex 사용법
Vuex 폴더 구조
일반적으로 src 폴더안에 store 폴더를 만든 후 index.js를 만들어 전역 저장소 파일로 사용해준다.

1. index.js 저장소 파일에 vuex에서 { createStore } import 해주기
import { createStore } from 'vuex';
2. createStore 함수의 인수로 옵션값 전달 한 후 기본값으로 내보내기
import { createStore } from 'vuex';
export default createStore({ 옵션 등록 });
3. main.js에 저장소 파일 index.js를 플러그인 형태로 등록해주기
import { createApp } from 'vue';
import store from './store/index.js';
import App from './App.vue';
createApp(App).use(store).mount('#app');
4. createStore에 옵션등록해주기
// index.js
import { createStore } from 'vuex';
export default createStore({
state() {
return {
// 데이터 (data)
};
},
getters: {
// 계산된 데이터 (computed state)
}
mutations: {
// state를 수정할 수 있는 메서드 (method to edit state)
// state의 수정권한을 가지고 있다
},
actions: {
// 컴포넌트에서 state에 접근할때 사용할 메서드 (method for components to access)
// mutations 옵션에서 만든 메서드를 가져와 컴포넌트에서 접근할 수 있도록 한다
method(context) {
const { state, getters, commit, dispatch } = context
// state: state에 접근할 수 있는 객체
// getters: getters에 접근할 수 있는 객체
// commit: mutations 옵션안에 있는 메서드를 호출하는 함수
// dispatch: actions 옵션안에 있는 메서드를 호출하는 함수
}
},
modules: {
// 저장소를 모듈화한 후 모듈화된 스토어 등록시 사용하는 옵션
}
});
옵션 설명
1. state
- 전역적으로 사용할 데이터를 state 옵션 안에 선언한다
- 선언된 데이터는 모든 컴포넌트에서 구조에 상관없이 접근할 수 있게 된다
2. getters
- 컴포넌트 script에 computed 옵션과 같은 역할을 한다
- 계산된 state를 값으로 지정하고 싶을때 getters 옵션을 사용한다
3. mutations
- mutations 옵션안에 있는 메서드는 state를 수정할 수 있다
- mutations에서는 state의 값을 수정할 권한이 있다 즉 state 데이터를 할당연산자(=)를 사용해 값을 재할당할 수 있다
- 다른 컴포넌트에서 state를 수정하고 싶으면 저장소 내부에 있는 mutations에 메서드를 만들어 수정해주어야 한다 (컴포넌트 내부에서 수정할수 없음)
- 비동기적 또는 동기적 코드 x 단순히 state를 재할당 o
4. actions
- mutations에 선언한 메서드를 가져와 컴포넌트에서 접근할 수 있도록 하는 옵션
- 다른 컴포넌트에서 state를 수정하고 싶으면 actions 안에 있는 메서드를 불러와 mutations 안에 있는 메서드를 실행시켜주어야 한다
- actions 옵션 안에 있는 모든 함수들은 async, await와 같은 키워드 없이도 비동기로 동작한다
- 비동기적 또는 동기적 코드 o 단순히 state를 재할당 x
- actions에서는 state의 값을 수정할 권한이 없기 때문에 state 데이터를 할당연산자를 사용해 값을 재할당 할 수는 없다. 고로 actions는 state값을 연산하고 mutations에 넘겨주는 역할까지만하고 state 값을 할당해주는 역할은 mutations에 맡겨야한다
- 이때 actions에서 선언한 메서드는 context라는 객체를 파라미터를 가진다
- context 객체에는 state, getters, commit, dispatch가 들어 있고 이를 구조분해할당문법을 사용해 꺼내준다
- state: state에 접근할 수 있는 객체
- getters: getters에 접근할 수 있는 객체
- commit: mutations을 호출하는 함수
- dispatch: actions를 호출하는 함수
5. modules
- index.js 저장소에 여러개의 데이터를 등록해 사용하다 보면 코드가 점점 길어지고 복잡해진다. 이를 해결하기 위해 비슷한 코드끼리 묶어 하나의 파일로 만들어주는 모듈화 작업을 해주어야하는데 이때 모듈화된 파일을 modules 옵션에 불러온다.
예제
1. store 폴더에 전역저장소 index.js 파일, count 관련 로직을 저장할 count.js 파일, message 관련 로직을 저장할 message.js 파일을 만들어준다

2. 만들어준 저장소를 플러그인 형태로 main.js에 등록해준다. 여기서 import store from './store' 코드는 index.js 파일을 default 값으로 불러온다
// main.js
import { createApp } from 'vue'
import store from './store'
import App from './App.vue'
createApp(App).use(store).mount('#app')
3. index.js 파일에서 사용할 저장소 createStore를 import 해주기
import { createStore } from 'vuex';
4. createStore 함수의 인수로 옵션값 전달 한 후 기본값으로 내보내기
import { createStore } from 'vuex';
export default createStore({ 옵션 등록 });
5. index.js 파일에서 다른 저장소 파일(message, count)을 modules 옵션에 등록해주기. 아래의 코드는 key와 value의 값이 같아 생략해준 형태다. 원래 코드는 message: message, count: count다.
// index.js
import { createStore } from 'vuex'
// 모듈 불러오기
import message from './message'
import count from './count'
export default createStore({
// 모듈 등록하기
modules: {
message,
count
}
})
이때 불러온 모듈을 다른 이름으로 등록해주고 싶다면 아래와 같이 사용할 수도 있다.
modules: {
// 불러온 message 모듈을 msg로 등록해주었다
msg: message,
count: count
}
6. count.js에서 데이터를 등록하기에 앞서 modules 옵션을 사용하기 위해 필요한 이름범위 namespaced: true값을 넣어준다.
// count.js
export default {
namespaced: true,
}
7. state 옵션에 count라는 데이터 등록해주기
// count.js
export default {
namespaced: true,
state() {
return {
count: 0,
}
},
}
8. 저장소에 등록한 데이터를 컴포넌트에서 사용하기 위해서는 등록해준 데이터(count)를 computed 옵션에 등록해주어야 한다. computed 옵션에 count라는 메서드를 만들어준 후 리턴값으로 저장소에 있는 데이터를 가져온다.
// HelloWorld.vue
<template>
// computed에 등록된 count 메서드 불러오기
<h1>{{ count }}</h1>
</template>
<script>
export default {
computed: {
count() {
// $ 키워드로 store에 접근, state 값 불러오기, count 모듈 안에 있는 count 값을 리턴
return this.$store.state.count.count
},
},
}
</script>
9. 스토어에 등록된 데이터를 수정하기 위해서는 반드시 등록된 데이터가 있는 모듈에서 그 작업이 이루어져야 한다 (컴포넌트 내부에서 임의로 수정 불가). 모듈 안에 state로 등록한 데이터는 mutations 옵션안에서 해당하는 state를 수정하는 메서드를 만들어 데이터를 수정한다. 아래의 코드는 count 스토어 모듈에 등록한 count 데이터의 값을 수정하기 위해 mutations 옵션안에 increase라는 메서드를 만들어 해당 값을 수정하는 로직을 넣어주었다.
// count.js
export default {
namespaced: true,
state() {
return {
count: 0
}
},
mutations: {
increase(state) {
state.count += 1
}
},
}
10. count 스토어에 등록한 count 데이터를 수정하는 메서드 increase를 컴포넌트 mehtods 옵션에 등록해준다. increase 메서드는 commit 함수를 사용해 count 스토어에 등록된 increase 메서드를 호출한다.
// HelloWorld.vue
<template>
<h1>{{ count }}</h1>
// 버튼을 클릭하면 메서드에 등록한 increase 함수가 실행된다
<button @click="increase">INCREASE + 1</button>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count.count
},
},
methods: {
increase() {
// mutations에 등록된 메서드를 호출하는 함수 commit을 사용
// count 스토어에 등록된 increase 메서드 호출하기
this.$store.commit('count/increase')
}
}
}
</script>
11. count 스토어에서 state를 수정하기 위해 mutations 옵션을 사용하였다. 하지만 가장 권장되는 방법은 mutations 옵션에서는 state의 재할당(수정)을 actions에서는 mutations에 선언한 메서드를 가져와 컴포넌트에서 접근할 수 있도록 하는 것이 좋다. 위의 예제에서는 mutations에서 state를 수정하고 컴포넌트에서 commit 함수로 mutations에 등록된 함수를 바로 호출했지만 가장 좋은 방법은 아니다. 앞으로는 actions 옵션에서 mutations에 등록된 메서드를 다시 호출해 컴포넌트가 actions에 등록된 함수를 호출하도록 하는 것이 좋다.
// count.js
export default {
namespaced: true,
state() {
return {
count: 0
}
},
// mutations: state 값 재할당 (수정)
mutations: {
// commit('setState', {넘겨줄값})으로 해당 메서드가 호출된다
// payload로 받아온 값 { count: state.count + 1 }
setState(state, payload) {
for (const key in payload) {
state[key] = payload[key]
}
}
},
// actions: 컴포넌트에서 mutations에서 만든 메서드를 가져와 컴포넌트에서 접근할 수 있도록 한다
actions: {
// context 객체에서 꺼내온 값 ({ state, commit })
// 1. state: 데이터가 저장되어 있는 곳
// 2. commit: mutations에 등록된 메서드를 호출시키는 함수
increase({ state, commit }) {
// commit('mutations에 등록된 호출시킬 메서드', { payload 파라미터로 넘겨줄값 })
commit('setState', {
count: state.count + 1,
})
},
}
}
문법정리
actions: {
method(context) {
const { state, getters, commit, dispatch } = context
},
}
actions에서 선언한 메서드는 context라는 객체를 파라미터를 가진다
context 객체에는 state, getters, commit, dispatch가 들어 있고 이를 구조분해할당문법을 사용해 꺼내준다
- state: state에 접근할 수 있는 객체
- getters: getters에 접근할 수 있는 객체
- commit: mutations을 호출하는 함수
- dispatch: actions를 호출하는 함수
$store의 메서드 두가지
- 메서드에서 사용하는 저장소 이름은 index.js에 modules의 key값을 가리킨다
- 즉 index.js에 modules의 key 이름과 method에서 사용하는 저장소 이름은 같아야한다
$store.method('저장소이름/함수이름', payload)
- commit(): mutations 안에 있는 함수를 실행할때 사용하는 메서드
- dispatch(): actions 안에 있는 함수를 실행할때 사용하는 메서드
- payload: 함수로 전달할 인자
12. 아래의 코드에서는 컴포넌트에서 dispatch 함수로 actions에 등록된 함수를 호출한다.
// HelloWorld.vue
<template>
<h1>{{ count }}</h1>
// count 모듈에 등록된 count 데이터 수정을 요청하는 버튼
// 버튼이 클릭될때마다 count의 값이 1씩 올라간다
<button @click="increase">INCREASE + 1</button>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count.count
},
},
methods: {
// increase 메서드에 count 스토어에서 만든 increase 함수를 호출한다
// 이때 actions에 등록된 함수 increase를 호출할 것이기 때문에 dispatch 함수를 사용한다
increase() {
this.$store.commit('count/increase')
}
}
}
</script>
13. mapState, mapActions 사용해서 저장소에 있는 여러 state와 메서드 한번에 등록한 후 사용해주기. 스토어에 등록된 state와 메서드를 불러올때마다 computed와 methods 옵션에 함수를 하나하나 만드는 작업은 저장해야할 데이터가 늘어날수록 그 작업이 힘들어진다. 등록된 모든 state와 메서드를 아래의 코드처럼 mapState와 mapActions를 사용해 등록해주면 편리하다
<template>
<h1>{{ count }}</h1>
<button @click="increase">
INCREASE + 1
</button>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
// count 스토어에 등록된 여러개의 state를 한번에 배열로 불러오는 작업
...mapState('count', ['count'])
// count 스토어에 등록된 state를 하나하나 불러오는 작업
// count() {
// return this.$store.state.count.count
// },
},
methods: {
// count 스토어에 등록된 여러개의 methods를 한번에 배열로 불러오는 작업
...mapActions('count', ['increase'])
// count 스토어에 등록된 methods를 하나하나 불러오는 작업
// increase() {
// this.$store.dispatch('count/increase')
// },
}
}
</script>
reference
'Vue' 카테고리의 다른 글
| [Vue] template에서 데이터 접근시 사용하는 키워드 $data 사용법 (0) | 2022.08.05 |
|---|---|
| [Vue] props로 문자 데이터가 아닌 다른 데이터(숫자, 객체, 선언한 데이터 등)을 전달하는 방법 (0) | 2022.07.06 |
| [Vue/한줄정리] 싱글 파일 컴포넌트(SFC)란? (0) | 2022.06.30 |
| [Vue] 컴포넌트 전역등록, 지역등록 (0) | 2022.06.30 |
| [Vue] vite.js로 Vue 프로젝트 시작하고 ESLint, 경로 별칭까지 설정해주기 (0) | 2022.06.30 |
댓글