본문 바로가기
  • 평범한 나의 개발공부 일지
나의 개발 기록/Vue

[ Vue.js] vuex (state, getter, mutation, actions) 기본 실습

by 블랑 블랑 2022. 8. 6.
반응형

* vuex store 모듈화가 된 후 기준 실습임 *

 

1. state

* state을 실행하기 위해서는 Commponent의 computed 영역 내에 작성을 해야한다.

 

state실습을 위한 store폴더 내에 index.jstestStore.js 

//testStore.js
const testStore = {
  namespaced: true,
  state: { // 공통 관리되는 상태값을 관리,  접근방법- this.$store.state.items
    count: 33,
  },
  getters: { // 공유되는 상태 값을 조회 로직을 관리, 접근방법 - this.$store.getters['경로명/함수명']

  },
  mutations: { // 상태 값을 변경하는 로직을 관리, 접근방법 - this.$store.commit('경로명/함수명')
   
  },
  actions: { // 비동기 통신 및 동작을 정의하고 관리, 접근방법 - this.$store.dispatch('경로명/함수명')
    
  },
};

export default testStore;



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

import testStore from '@/store/testStore';
import joinStore from '@/store/joinStore';
import loginStore from '@/store/loginStore';

Vue.use(Vuex);

export default new Vuex.Store({
  strict: true,
  modules: {
    testStore,
    joinStore,
    loginStore,
  },
});

 

1) Vue 구성 요소에 Vuex 상태 가져오기

 

//CounterA.vue
<template>
  <div> {{ count }} </div>
</template>

<style scoped>
</style>



<script>
export default {
  computed: {
    count() {
      return this.$store.state.testStore.count
    }
  }
}
</script>

 

 

#화면 출력 결과

 

2) mapState

- state의 helper함수이다. 

* helper함수 ? vuex를 좀더 깔끔하고 간결하게 사용할 수 있게 도와주는 함수, 코드가 길어지는걸 대비할 수 있다.

 

 

<template>
  <div> {{ count }}  </div>
</template>

<style scoped>
</style>


<script>
import { mapState } from 'vuex'

export default {
  computed: 
  mapState({
      count: state => state.testStore.count,
    })
}
</script>

 

하지만 더 간결하게 하는 방법이있다

mapState{ }...mapState{[ ]} 로 바꿔주면 된다.

<template>
  <div> {{ count }}  </div>
</template>

<style scoped>
</style>



<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState('testStore',[
        'count'
    ])

  }
}
</script>

 

 

#화면 출력 결과 ( * 1)과 동일한 결과 )

 

 

 

 

 

2. getter

* getters을 실행하기 위해서는 Commponent의 computed 영역 내에 작성을 해야한다.

 

getter 실습을 위한 store폴더 내에 index.js

const testStore = {
  namespaced: true,
  state: { 
    todos: [
      {id : 1, text: "안녕하세요", done: true},
      {id : 2, text: "안녕히계세요", done: false},
    ]
  },
  getters: { 
    doneTodos(state){
      return state.todos.filter(todo => todo.done)
    }
  },
  mutations: { 
  },
  actions: { 
  },
};

export default testStore;

 

 

 

1) getters 접근 기본 ①

<template>
  <div> {{ doneTodosCount }}  </div>
</template>

<style scoped>
</style>



<script>
import { mapState } from 'vuex'

export default {
  computed: {
     doneTodosCount (){
      return this.$store.getters['testStore/doneTodos']
     }
  }
}
</script>

 

# 화면 출력 결과

- 이런식으로 getters는 메서드를 통해 호출했을 경우 가장 '첫번째 요소' 의 값만 반환한다

 

 

 

 

2) getters 접근 기본 ②

<template>
  <div> {{ doneTodosCount }}  </div>
</template>

<style scoped>
</style>



<script>
import { mapState } from 'vuex'

export default {
  computed: {
     doneTodosCount(){
      return this.$store.state.testStore.todos.filter(todo => todo.done).length
     }
  }
}
</script>

 

# 화면 출력 결과

todo.done이 true인 length를 반환한다

      {id : 1, text: "안녕하세요", done: true},
      {id : 2, text: "안녕히계세요", done: true},

만약 위와 같다면 결과는  2 가 나오게 된다. 

 

 

 

 

3) 속성 스타일 액세스

- getter는 store.getters  객체에 노출되며 속성으로 값에 액세스 한다.

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

- getters는 두 번째 인수로 다른 getter도 받을 수 있다.

  getters: {
    // ......
    doneTodoCount(state, getters){
      return getters.doneTodos.length
    }
  },

위와같이 두번째인자에 getters를 넣어 다른 getters를 받는 예제이다.

 

<template>
  <div> {{ doneTodosCount }}  </div>
</template>

<style scoped>
</style>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
     doneTodosCount(){
      return this.$store.getters['testStore/doneTodoCount']
     }
  }
}
</script>

 

 

# 화면 출력 결과

 

 

 

 

 

4) 메서드 스타일 액세스

- 함수를 반환하여 getter에 인수를 전달할 수 도 있다.

  getters: {
    // ......
    getTodoById : (state) => (id) => {
      return state.todos.find(todo => todo.id === id)
    }
  },
<template>
  <div> {{ doneTodosCount }}  </div>
</template>

<style scoped>
</style>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
     doneTodosCount(){
      return this.$store.getters['testStore/getTodoById',1]
    }
  }
}
</script>

얘는 실패..

doneTodosCount(){
      return this.$store.getters['testStore/getTodoById',1]

}

에서 인수전달 하는데 있어서 문제가 생긴것 같다... 

** 추후 성공해서 수정하기!!!!!!!!! ^^ 

 

 

 

 

5) mapGetters

    {
      ...mapGetters('testStore',[
        'doneTodos'
    ]),
    doneTodosCount(){
      return this.doneTodos
    }

    }

 

 

 

# 화면 출력 결과

 

 

 

 

 

3. mutation

 

1) mutation 접근 기본 

 

store폴더 내에 index.js

  state: {
    tardy: 0,
  },
  mutations: {
    addTardy(state) {
      state.tardy++;
    },
  },

 

 

<template>
  <div>
    mutation test :
    <b-button @click="addTardy">
      버튼
    </b-button>
  </div>
</template>

<style scoped>
</style>


<script>

export default {
  methods:
    {
      addTardy(){
        this.$store.commit('testStore/addTardy');
        console.log(this.$store.state.testStore.tardy)
      }
    }

}
</script>

버튼을 클릭하면 state에 있는 tardy가 1씩 증가하면 그걸 콘솔창에 나오게끔 만들었다.

 

# 화면 출력 결과

2) 인자값 전달 ①

 

store폴더 내에 index.js

  state: {
    tardy: 0,
  },
  mutations: {
    addTardy2(state, n){
      state.tardy += n
    }
  },

 

<template>
  <div>
    mutation test :
    <b-button @click="addTardy">
      버튼
    </b-button>
  </div>
</template>

<style scoped>
</style>


<script>

export default {
  methods:
    {
      addTardy(){
        this.$store.commit('testStore/addTardy2',10);
        console.log(this.$store.state.testStore.tardy)
      }
    }

}
</script>

commit('경로명/함수명',인자값) 을 넣어 인자를 전달할수있다

그래서 인자값 10을 보내면

addTardy2(state, n){
      state.tardy += n

}

에 의해 state의 tardy값이 초기값0에서 10씩 증가하는 모습을 볼수있다.

 

# 화면 출력 결과

 

 

 

 

3) 인자값 전달(feat. payload) ② 

 

store폴더 내에 index.js

  state: {
    tardy: 0,
  },
  mutations: {
    addTardy3(state, payload){
      state.tardy += payload.amount
    }
  },
<template>
  <div>
    mutation test :
    <b-button @click="addTardy">
      버튼
    </b-button>
  </div>
</template>

<style scoped>
</style>


<script>

export default {
  methods:
    {
      addTardy(){
        this.$store.commit('testStore/addTardy3', {
          amount: 10
        });
        console.log(this.$store.state.testStore.tardy)
      }
    }

}
</script>

위와 같이 인자값에 저런식으로 넣어주면 payload를 이용하여 접근할 수 있다

 

# 화면 출력 결과

 

 

위에 방법을 조금 변형해본다면?

methods:
    {
      addTardy(){
        this.$store.commit({
          type: 'testStore/addTardy3',
          amount: 10
        });
        console.log(this.$store.state.testStore.tardy)
      }
    }

commit('경로명/함수명',인자값) 

대신

commit({ type: '경로명/함수명' , 키: 값 }) 으로 바꿔주었다

 

결과는 같다.

 

 

 

 

 

 

4. actions

 

1) 기본 ①

 

store폴더 내에 index.js

  state: {
    tardy: 0,
  },
  mutations: {
    addTardy3(state, payload){
      state.tardy += payload.amount
    }
  },
  actions: {
    addTardy(result) {
      result.commit('addTardy');
    },
  },
<template>
  <div>
    mutation test :
    <b-button @click="addTardy">
      버튼
    </b-button>
  </div>
</template>

<style scoped>
</style>


<script>

export default {
  methods:
    {
      addTardy(){
        this.$store.dispatch('testStore/addTardy');
        console.log(this.$store.state.testStore.tardy)
      }
    }

}
</script>

 

# 화면 출력 결과

 

actions: {
    addTardy(result) {
      result.commit('addTardy');
    },
  },

위 코드를 를 더 간결하게 할 수도 있다 ▼ 

actions: {
    addTardy( {commit} ) {
      commit('addTardy');
    },
  },

 

 

 

 

2) 기본 ②

 

store폴더 내에 index.js

  state: {
    tardy: 0,
  },
  mutations: {
    addTardy3(state, payload){
      state.tardy += payload.amount
    }
  },
  actions: {
    addTardy2 ( {commit }){
      setTimeout(() => {
        commit('addTardy')
      }, 1000)
    }
  },

 

<template>
  <div>
    mutation test :
    <b-button @click="addTardy">
      버튼
    </b-button>
  </div>
</template>

<style scoped>
</style>


<script>

export default {
  methods:
    {
      addTardy(){
      this.$store.dispatch('testStore/addTardy2')
      console.log(this.$store.state.testStore.tardy)
      }
    }

}
</script>

요렇게 지정된 시간이 지나면 함수를 실행하는 setTimeOut을 이용해서 코드를 짤 수 도 있다

1000 > 10초인데 10초마다 state의 tardy가 1씩 증가한다.

 

 

 

 

3) mapActions

- 추후 추가하기

 

 

 

4) promise

프로미스의 resolve, reject는 비동기 작업의 처리과정에서 성공/실패를 구분하는 방법이다.

- promise 객체와 resolve를 할당받은 메소드만이 async와 await 키워드를 사용할 수 있다.

- promise 객체를 부여받은 메소드는 내부에는 resolve() 메소드를 부여한다.

- await 키워드를 할당받은 메소드는 promise 내부에서 resolve()가 실행될 때까지 우선적으로 실행된다. 

- resolve()가 실행되기 전까지 다른 메소드는 실행될 수 없다.

출처: https://devraphy.tistory.com/229 [개발자를 향하여:티스토리]

 

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}


store.dispatch('actionA').then(() => {
  // ...
})

쉽게 말하면 비동기 처리를 순서대로 실행시키기 위한 기능이다

만약 promise가 없으면 함수에서 콜백>콜백>콜백 이런식으로 되어서 가독성도 좋지 않고 힘들다고 한다.

resolve 함수는 성공시, reject는 실패할때 사용된다.

위에 resolve나 reject가 둘중 한개라도 있어야 다음 then으로 넘어간다.

 

 

 

 

 

 

 

 

 

 

반응형

댓글