참고: https://vuex.vuejs.org/guide/state.html#getting-vuex-state-into-vue-components
참조: https://v3.vuex.vuejs.org/guide/getters.html
VuexPractice.vue
<template>
<div>
<b-button @click="clickAction">
메롱
</b-button>
</div>
</template>
<script>
export default {
methods: {
clickAction(){
this.$store.commit('increment')
console.log(this.$store.state.count)
}
},
}
</script>
VuexPractice.store.js
const vuexPraticeModule ={
state: {
count:0
},
mutations: {
increment(state){
state.count++
}
}
}
export default vuexPraticeModule
store.js
//import router from "@/router";
import Vue from "vue";
import Vuex from "vuex";
import loginModule from "./loginModule";
import vuexPraticeModule from "./VuexPratice.store"
Vue.use(Vuex);
// store는 페이지 새로고침시 데이터가 초기화된다. -> localStorage를 이용
export default new Vuex.Store({
modules:{
loginModule,
vuexPraticeModule,
}
});
근데 console창에 undefined 가 뜬다
this.$store.state 로 찍었는데 저렇게 안에 잇는데도... 나오지않는다... 모르겟다.. 그러니 일단 넘어가보자!
내생각엔, module화를 함에 있어서 뭔가 내가 잘못한 부분이 있는 것 같다. 그래서 그냥 store.js 에 module화 시켰던 부분을 그냥 넣었더니 잘 작동하더라!
//import router from "@/router";
import Vue from "vue";
import Vuex from "vuex";
import loginModule from "./loginModule";
Vue.use(Vuex);
// store는 페이지 새로고침시 데이터가 초기화된다. -> localStorage를 이용
export default new Vuex.Store({
modules:{
loginModule,
},
// 모듈화로 뺏던 부분을 넣었다
state:{
count:0
},
mutations: {
increment(state){
state.count++
}
}
});
그리고, 역시나 새로고침하면 count는 다시 시작된다
뒤에까지 모두 공부한 후에 왜 안됬는지 공부해야함!!!!
When using a module system, it requires importing the store in every component that uses store state, and also requires mocking when testing the component. 여기에 아마 키가 있지 않나 싶다. 하지만 잠시 넘어가자
전역으로 저장해서 사용해보기
main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import axios from "axios";
new Vue({
router,
store,
render: (h) => h(App),
computed:{
count(){
return this.$store.state.count
}
}
}).$mount("#app");
VuexPractice.vue
<template>
<div>
{{ count }}
</div>
</template>
<script>
export default {
}
</script>
하지만 App 에는 count 가 존재하지않았다.
그래서, 다시 생각해낸 방법 -> 전역으로 가지고 있는게 아닌것같으니 vuex를 전역으로 가지게해보자
main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state:{
count:0
}
})
new Vue({
router,
store,
render: (h) => h(App),
computed:{
count(){
return this.$store.state.count
}
}
}).$mount("#app");
App과 Root에 모두 count가 찍혓는데.... 왜 도대체가 VuexPractice 컴포넌트에는 안찍히는거니.. 혹시 props로 주고받는거해야하니? 근데.. 공식문서에서는 됫자나!!!!!!!!!!
Vuex provides a mechanism to "inject" the store into all child components from the root component with the store option (enabled by Vue.use(Vuex)):
성공한거!!!! >>>> By providing the store option to the root instance, the store will be injected into all child components of the root and will be available on them as this.$store.
여기서 힌트를 얻엇다!!!main.js
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import Vuex from 'vuex'
Vue.use(Vuex);
const Counter = {
template: `<div>{{count}}</div>`,
computed:{
count(){
return store.state.count
}
}
}
new Vue({
router,
store,
components: {Counter},
template: `<div class="app"><counter></counter></div>`,
render: (h) => h(App),
}).$mount("#app");
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count: 12
},
});
VuexPractice.vue
<template>
<div>
{{ count }}
<b-button>
메롱
</b-button>
</div>
</template>
<script>
export default {
computed:{
count(){
return this.$store.state.count
}
}
}
</script>
성공했다ㅏㅏㅏㅏ
아무리 Root에 있다고 하지만, 그래도 state에 접근해있는 변수를 가져오는 것이기때문에 $store에 접근해서 가져와야한다!
mapState helper
state에 너무 많은 변수들이 선언되어있을 때 쉽게 사용하기 위함이라고한다.
mapState helper which generates computed getter functions for us, saving us some keystrokes:
Getters
Vuex allows us to define "getters" in the store. You can think of them as computed properties for stores. Like computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.
Getter는 컴포넌트의 computed와 비슷한 역할을 수행한다. 즉, Vuex Store로부터 상태 값을 읽어올 때 바로 읽어오는 것이 아니라 해당 상태 값을 활용해 계산된 속성으로 읽어오게 된다. 예를 들면, 특정 배열 상태 값이 있다고 할 때 해당 상태 값의 길이를 읽어오는 Getter를 생성해 사용할 수 있다.
store.js
import Vue from "vue";
import Vuex from "vuex";
import axios from 'axios'
Vue.use(Vuex);
export default new Vuex.Store({
state:{
user: [
{userName: '박민아', userRole: '팀원'},
{userName: '김지아', userRole: '팀원'}
],
isLogin: false,
},
getters:{
getUserByName: (state)=>(userName)=>{
return state.user.find(user => user.userName === userName)
}
},
});
VuexPractice.vue
<template>
<div>
<b-input />
<b-button @click="clickEvent">
메롱
</b-button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
methods:{
clickEvent(){
console.log(this.$store.getters.getUserByName('박민아'))
},
}
}
</script>
잘찍혓다!
mapGetters
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count: 12,
user: [
{userName: '박민아', userRole: '팀원'},
{userName: '김지아', userRole: '팀원'}
],
isLogin: false,
},
getters:{
getUserByName: (state)=>(userName)=>{
return state.user.find(user => user.userName === userName)
}
},
});
VuexPractice.vue
<template>
<div>
<b-button @click="clickEvent">
메롱
</b-button>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed:{
...mapGetters(['getUserByName']),
},
methods:{
clickEvent(){
console.log(this.getUserByName('박민아'))
},
}
}
</script>
그러면 , this. 으로 getters에 있는 값에 접근이 가능하다!
잘찍혓구만
mutations
One important rule to remember is that mutation handler functions must be synchronous. Why?
Now imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a "before" and "after" snapshot of the state. However, the asynchronous callback inside makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called - any state mutation performed in the callback is essentially un-trackable!
store.js
import Vue from "vue";
import Vuex from "vuex";
import axios from 'axios'
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count: 12,
user: {userName: null, userRole: '팀원'},
},
getters:{
getUserInfo: state => state.user,
},
mutations:{
setUserName: (state, payload) => state.user.userName = payload
},
actions:{
getUserinfo({ commit }, loginEmail){
return axios.post('/api/getUserInfo',{ userEmail:loginEmail })
.then(function(response){
console.log(response)
commit("setUserName", response.data.NAME);
})
.catch(function(){
console.log('실패');
})
},
}
});
VuexPractice.vue
<template>
<div>
<b-input v-model="loginEmail" />
<b-button @click="clickEvent">
메롱
</b-button>
{{ loginUserName }}님
</div>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
export default {
data(){
return{
loginEmail: "",
loginUserName: "",
}
},
computed:{
...mapGetters(['getUserByName', 'getUserInfo']),
...mapMutations(['setIsLogin']),
},
methods:{
clickEvent(){
this.$store.dispatch("getUserinfo", this.loginEmail)
console.log('axios 후에 user' + this.$store.state.user)
this.loginUserName = this.getUserInfo.userName
},
}
}
</script>
여기서 발견한 신기한 점!!!! >>>> console을 지금 dispatch 후에 찍어두고, axios 의 then 에 찍어뒀는데!!!! 놀라운 사실, console에 찍힌 순서를 보면 먼저 dispatch 후에 찍혀야하는 그 console이 먼저 찍혔다!
이건 비동기의 문제라고 생각한다! 전에 배운것처럼 언제 뭐가 먼저 실행될지 모르는 것이기때문에, 먼저 axios가 완료되면 그 다음으로 넘어가게 해줄 수 있게 설정해줘야한다고 배웠다!
첫번째, 그래서 VuexPractice.vue 에서 axios 실행되는 dispatch 부분을 수정했다.
async 와 await 를 이용해서 보완해봤다!!! async/await
먼저 함수 내에서 await 을 사용하기 위해 함수앞에 async 를 넣어준다. await 을 사용하여 요청을보내면 응답받은 값을 같은 스코프 내에서 처리가 가능해져서 훨씬 보기도 편하고, 코드도 간결해지고 콜백 지옥 현상도 발생하지 않는다.
methods:{
async clickEvent(){
await this.$store.dispatch("getUserinfo", this.loginEmail)
console.log('axios 후에 user' + this.$store.state.user.userName)
this.loginUserName = this.getUserInfo.userName
},
}
순서대로 console이 찍힌 것을 볼 수가 있다!
하지만, 여전히 state의 user는 setting 되어있지 않다. 그렇다는 말은 action안에서도 순서대로 실행될 수 있도록 설정해주면 바뀌는지 확인해보자!
그래서 수정한 main.js 의 actions 부분
actions:{
async getUserinfo({ commit }, loginEmail){
return await axios.post('/api/getUserInfo',{ userEmail:loginEmail })
.then(function(response){
console.log(response)
commit("setUserName", response.data.NAME);
})
.catch(function(){
console.log('실패');
})
},
}
성공!!!
떴다!!!!
'웹앱프로젝트 > Vue.js' 카테고리의 다른 글
Vuex 이용한 회원가입 구현 (vuex actions context의 사용) (0) | 2022.08.29 |
---|---|
Vuex의 actions, modules 기본실습 ( + promise, async/await 설명) (0) | 2022.08.18 |
router-link 의 to 의 path를 props 로 주고받기 (0) | 2022.07.31 |
router 에 path 와 children 활용 (0) | 2022.07.31 |
Vue 프로젝트 생성 (visual studio code) (0) | 2022.05.25 |