반응형
기존 Vuex를 사용할 때 불편함
this.$store.state.변수명을 가지게 되면 컴포넌트가 많아질수록 추적하기 어렵다.
<template>
<div>
<transition-group name="list" tag="ul">
<!-- this.$store.state.todoItems 컴포넌트가 많아질수록 추척이 어렵다.-->
<li class="shadow" v-for="(todoItem, index) in this.$store.state.todoItems" :key="index">
<i class="checkBtn" :class="{ checkBtnCompleted: todoItem.completed }" @click="completeTodoItem({ todoItem, index })">V</i>
<span :class="{ textCompleted: todoItem.completed }">{{ todoItem.item }}</span>
<span class="removeBtn" @click="removeTodoItem({ todoItem, index })">
<i>삭제</i>
</span>
</li>
</transition-group>
</div>
</template>
Vue.js 스타일 가이드
컴포넌트 템플릿에는 단순한 표현식만 포함하고, 복잡한 표현식은 계산된 속성이나 메서드로 리팩터링 하자
- 템플릿에 복잡한 표현식이 있으면 선언적 표현이 줄어들기 때문
또한 값을 계산하는 '방법'이 아니라 '무엇'이 표시되어야 하는지를 설명하기 위해 노력하면 계산된 프로퍼티와 메서드는 코드를 재사용할 수 있다.
분리 한다면 computed를 통해 만든 계산된 데이터는 캐싱의 이점을 얻을 수 있다.
- 한 번 연산해놓은 값을 반복적으로 출력할 때 다시 한번 연산하지 않음
<script>
export default {
data() {
return {
msg: 'Hello Computed'
}
},
computed: {
reversedMessage() {
return this.msg.split('').reverse().join('')
}
}
}
</script>
Vuex Helper 란?
Store에 있는 4가지 속성을 간편하게 작성할 수 있다.
- state: mapState
- getter: mapGetters
- mutations: mapMutations
- actions: mapActions
기존 사용 방법
- Vuex에서 선언한 속성을 뷰 컴포넌트에 쉽게 연결해주는 helper들이다.
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
computed: {
...mapStore(['num']),
...mapGetters(['countedNum'])
},
methods : {
...mapMutations(['clickBtn']),
...mapActions(['asyncClickBtn'])
}
}
</script>
- ...(Object Spread Operator)를 사용하는 이유는 기존의 computed의 내부 속성과 같이 사용하기 위함이다.
mapState
// App.vue
import { mapState } from 'vuex'
computed: {
//num() { return this.$store.state.num; }로 작성하지 않아도 된다.
...mapState(['num'])
}
// store.js
state: {
num: 10
}
mapGetters
// App.vue
import { mapGetters } from 'vuex'
computed {
...mapGetters(['reverseMessage'])
}
// store.js
getters: {
reverseMessage(state){
return state.msg.split('').reverse().join('');
}
}
mapMutations
// App.vue
import { mapMutations } from 'vuex'
methods:
...mapMutations(['clickBtn'])
}
// store.js
mutations: {
clickBtn(state){
alert(state.msg);
}
}
mapActions
// App.vue
import { mapActions } from 'vuex'
methods:
...mapActions(['delayClickBtn']),
}
// store.js
actions: {
delayClickBtn(context){
setTimeout(() => context.commit('clickBtn', 2000);
}
}
헬퍼의 유연한 문법
vuex에 선언한 속성을 그대로 컴포넌트에 연결하는 문법
//배열 리터럴
...mapMutations({
'clickBtn', //'clickBtn' : clickBtn
'addNumber' //addNumber(인자)
])
vuex에 선언한 속성을 컴포넌트의 특정 메서드에다가 연결하는 문법
// 객체 리터럴
...mapMutations([
// 컴포넌트 메서드 명 : Store의 Mutataion명
popupMsg : 'clickBtn'
])
👻 script setup에서 Vuex Helper 사용하기
libs/todoHelper.js로 파일을 하나 만들어줬다.
import { computed } from 'vue'
import { useStore } from 'vuex'
const mapState = () => {
const store = useStore()
return Object.fromEntries(
Object.keys(store.state).map(
key => [key, computed(() => store.state[key])]
)
)
}
const mapGetters = () => {
const store = useStore()
return Object.fromEntries(
Object.keys(store.getters).map(
getter => [getter, computed(() => store.getters[getter])]
)
)
}
const mapMutations = () => {
const store = useStore()
return Object.fromEntries(
Object.keys(store._mutations).map(
mutation => [mutation, value => store.commit(mutation, value)]
)
)
}
const mapActions = () => {
const store = useStore()
return Object.fromEntries(
Object.keys(store._actions).map(
action => [action, value => store.dispatch(action, value)]
)
)
}
export { mapState, mapGetters, mapMutations, mapActions }
코드를 이해하지 못하겠으면 아래 링크로 들어가서 읽어보자
구조 분해 할당을 통해서 쉽게 사용할 수 있다.
<script setup>
import { mapGetters, mapMutations } from '@/libs/todoHelper';
const { getTodoItems } = mapGetters();
const { removeTodoItem, completeTodoItem } = mapMutations();
</script>
컴포넌트 템플릿에서 getTodoItems로 간결하게 사용할 수 있다.
<template>
<div>
<transition-group name="list" tag="ul">
<!-- getTodoItems로 간결하게 사용할 수 있다. -->
<li class="shadow" v-for="(todoItem, index) in getTodoItems" :key="index">
<i class="checkBtn" :class="{ checkBtnCompleted: todoItem.completed }" @click="completeTodoItem({ todoItem, index })">V</i>
<span :class="{ textCompleted: todoItem.completed }">{{ todoItem.item }}</span>
<span class="removeBtn" @click="removeTodoItem({ todoItem, index })">
<i>삭제</i>
</span>
</li>
</transition-group>
</div>
</template>
📚 Reference
- https://www.inflearn.com/course/vue-pwa-vue-js-%EC%A4%91%EA%B8%89/dashboard
- https://stackoverflow.com/questions/64010072/how-to-use-vuex-mapgetters-with-vue-3-sfc-script-setup-syntax
반응형