
지금까지는 바로 api를 받아 컴포넌트로 뿌려주었지만, 이렇게 되면 안 좋은 점이 매번 api를 생성해주고 import로 index.js를 불러와 해당 함수를 등록해주어야한다.
코드가 복잡해짐은 물론 한 줄이라도 코드가 더 늘어나니 이를 줄일 수 있으면 좋을 것 같다.
-> 그래서 사용하게 된 것이 Vuex 라이브러리 !!
" 상태 관리 도구 = vuex "
상태라는 것은 여러 컴포넌트 간에 공유되는 데이터
- 모든 것들을 하나의 공간에서 관리해주는 것이 필요한데, Vue에서는 전역에 공유되는 상태 관리를 위해 vuex를 이용한다.
- 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소를 제공하는 라이브러리다.
vuex는 vue.js 애플리케이션 상태 관리 패턴 + 라이브러리라고 공식 홈페이지에서 설명하고 있다.

vuex는 state, mutations, actions 등 여러가지 속성들이 있고, 이를 활용해 데이터를 조작하기 때문에 다룰 데이터가 많아지고 설정할 것이 많아지면 애플리케이션의 구조를 확인할 수 있는 main.js가 복잡해진다.
이럴 때에는 따로 store 폴더를 만들어 index.js를 생성하고 이를 main.js에 등록하는 것이 코드를 분리하고 더 깔끔하게 다룰 수 있도록 도와준다.
import Vue from 'vue'
import App from './App.vue'
import {store} from './store/index.js';
import {router} from './router/index';
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router, store
}).$mount('#app')
import Vue from 'vue';
import Vuex from 'vuex';
import {fetchNewsList} from "../api/index.js";
Vue.use(Vuex);
export const store = new Vuex.Store({
state:{
news:[]
},
mutations:{
//state로 데이터를 넘기기 때문에 첫 인자는 무조건 state로 해야한다.
SET_NEWS(state, news){
state.news = news;
}
},
actions: {
FETCH_NEWS(context){
fetchNewsList()
.then(response=>{
console.log(response);
context.commit('SET_NEWS',response.data);
//state.news=response.data;
})
.catch(error => {
console.log(error);
});
}
}
// getters,
// mutations,
// actions
})
구조상 actions에서 state로 바로 데이터를 바인딩 할 수 없다.
actions에서는 mutations을 거쳐 state로 가기 때문에
mutations에서 이를 담아주는 함수를 실행해야함.
actions에서는 mutations에 접근할 수 있게 context가 제공된다.
context.commit으로 해당 mutations에 접근할 수 있다.
(context는 actions에서 mutation에 접근할 수있도록 제공하는 것)
Vue가 Vuex를 사용할 수 있게 Vue.use(Vuex)를 선언해준다.
이후 나오는 모든 속성들은 외부로 export되어 컴포넌트에서 사용되기 때문에 위와 같이 관리한다.
export const store = new Vuex.Store({ state : {}, mutations : {}, actions : {}, ... });actions에서는 데이터 api를 받아오는 역할,
mutations에서는 데이터를 다루는 함수 등을 작성,
state에서는 해당 데이터를 저장해 사용할 수 있도록 만드는 것
actions : {
FETCH_NEWS(context) {
fetchNewsList()
.then(response => {
context.commit('SET_NEWS', response.data);
})
.catch(error => {
console.log(error);
});
}
}
FETCH_NEWS를 통해 routes에 정의해놓은 fetchNewsList()를 실행한다. 해당 함수는 axios를 통해 정해진 url에서 데이터를 받아오고
🔎 api > index.js 에서 해당 함수를 import 해와야 한다.
그 데이터가 성공적으로 들어오면(.then) context.commit을 통해 mutations로 해당 데이터를 넘겨준다는 뜻이다.
여기서 context는 actions에서 mutations에 접근할 수 있도록 제공하는 것으로 아래처럼 사용해 데이터 전달이 가능하다.
context.commit('전송할 mutations 함수의 이름', 전송할 데이터);
다시 코드를 보면 SET_NEWS라는 mutations으로 데이터가 넘어가게 된다. 그럼 해당 mutations를 보자
mutations: {
//state로 데이터를 넘기기 때문에 첫 인자는 무조건 state로 해야한다.
SET_NEWS(state, news) {
state.news = news;
}
}
mutations에서는 이후 state로 데이터가 옮겨가기 때문에 첫 번째 인자로 꼭 state를 넣어야한다.
이전에 vm을 생성해서 데이터를 넣어야 전달이 되던 것 처럼 state 인자를 통해 state.변수이름 = 데이터;를 사용해야한다.
<template>
<div>
<div v-for="user in this.$store.state.news">{{ user.title }}</div>
</div>
</template>
<script>
export default {
created() {
this.$store.dispatch('FETCH_NEWS');
}
}
</script>
<style>
</style>
위와같이 데이터를 받아올 수 있다. store를 통해 정의한 state 안의 데이터들은 어느 컴포넌트에서든지 this.$store.state.데이터이름을 통해 호출할 수 있기 때문에 그만큼 관리가 편해진다.
created도 store/index.js에서 데이터를 부르는 actions를 선언하는 것 만으로 원하는 데이터를 호출할 수 있다.
created() {
this.$store.dispatch('FETCH_NEWS');
}
중앙 집중식 저장소라고 생각하면 편하고, 로직이 굴러가는 과정을 잘 아는 것이 중요하다!!
해당 컴포넌트에서 mapState 를 이용해서 데이터값을 가져와보자.
<template>
<div>
<div v-for="(ask, i) in ask" :key="i">
{{ask.id}}
</div>
</div>
</template>
<script>
import {mapState} from "vuex";
export default {
computed:{
...mapState({
ask : state => state.ask
}),
},
created() {
this.$store.dispatch('FETCH_ASKS');
}
}
</script>
mapState를 통해 ask를 담고 template 에서 ask의 배열길이만큼 출력했다.
ask : state => state.ask 에서 앞 ask는 작명하면 되고 뒤의 state.ask는 스토어 안 mutation의 값이다.
이 방법도 복잡하다는 생각이 들 때 사용하는 것이 있다. "Getters"!!!
( store > index.js )
export const store = new Vuex.Store({
state:{
ask:[],
},
getters:{
fetchedAsk(state){
return state.ask;
}
},
mutations:{
SET_ASK(state, ask){
state.ask = ask;
}
},
actions: {
FETCH_ASKS({commit}){
fetchAskList()
.then(({data})=>{
// console.log(response);
commit('SET_ASK', data);
})
.catch(error=>{
console.log(error);
})
}
}
( view > AskView.vue )
<template>
<div>
<div v-for="(ask, i) in fetchedAsk" :key="i">
{{ask.id}}
</div>
</div>
</template>
<script>
import {mapGetters, mapState} from "vuex";
export default {
name: 'AskView',
computed: {
...mapGetters([
'fetchedAsk'
])
},
created() {
this.$store.dispatch('FETCH_ASKS');
}
}
</script>
<style></style>
그리고 스토어 속성을 모듈화 할 수도 있다. 예를들어 store 폴더 안에 mutation.js 나 action.js 이렇게 모듈화할 수 있는 것이다.

index.js 안에 있는 mutation의 내용들을 뜯어와서 새로 만든 mutaion.js 파일에 붙여넣기!
export default {
SET_NEWS(state, news){
state.news = news;
},
SET_JOBS(state, jobs){
state.jobs = jobs;
},
SET_ASK(state, ask){
state.ask = ask;
}
}
그리고 원래의 index.js 에서는
import mutation from "@/store/mutation";
export const store = new Vuex.Store({
state:{
news:[],
jobs:[],
ask:[],
},
getters:{
fetchedAsk(state){
return state.ask;
}
},
mutaion,
//mutations: mutation
//앞뒤가 같기때문에 mutation하나만 적어도 된다.
,
actions: {
FETCH_NEWS(context){
fetchNewsList()
.then(response=>{
console.log(response);
context.commit('SET_NEWS',response.data);
//state.news=response.data;
})
.catch(error => {
console.log(error);
});
},
FETCH_JOBS({commit}){
fetchJobsList()
.then(({data})=>{
commit('SET_JOBS', data);
})
.catch(error=>{
console.log(error);
})
},
FETCH_ASKS({commit}){
fetchAskList()
.then(({data})=>{
// console.log(response);
commit('SET_ASK', data);
})
.catch(error=>{
console.log(error);
})
}
}
// getters,
// mutations,
// actions
})
mutaion : mutation (앞뒤가 같으니까 mutaion만 적어도 됨) 처럼 import 하면 된다.