크기가 큰 프로젝트를 작업하다 보면 Vuex를 한곳에서 관리하기가 힘들어 지게 됩니다. Store를 모듈화 해서 상태를 관리하게 된다면 좀더 직관적이게 확인할수 있습니다.
저희가 진행하는 TodoList같은 경우 규모가 작아 굳이 사용할 필요 없지만, 큰 프로젝트를 진행한다고 생각하고 진행해 보겠습니다.
// src/store/Todos/todoList.ts
interface State {
todoList: TodolistType[];
}
interface TodolistType {
text: string;
completed: any;
}
const state: State = {
todoList: [
{
text: "test-todo1",
completed: false,
},
{
text: "test-todo2",
completed: true,
},
{
text: "test-todo3",
completed: false,
},
],
};
const mutations = {
deleteTodo(state: State, index: number) {
console.log(state, "state");
state.todoList.splice(index, 1);
},
compelete(state: State, index: number) {
state.todoList[index].completed = !state.todoList[index].completed;
},
addTodo(state: State, text: string) {
const todo = {
text,
completed: false,
};
state.todoList.push(todo);
},
};
export default {
namespaced: true,//namespaced
state,
mutations,
State,
};
store/index에 작업했던 store를 Todos/todoList.ts 로 옮겨와 줍니다.
전에 했던것과 거의 다 비슷한데 namespaced는 처음 보실겁니다.
namespaced란 store를 modules화 했을 때 true로 설정하게 된다면 각 모듈의 이름을 포함한 Dispatch, Commit, state조회 등을 작업할 수 있습니다.
//store/index.ts
import Vue from "vue";
import Vuex from "vuex";
import todoList from "./Todos/todoList";
Vue.use(Vuex);
export default new Vuex.Store({
modules: { todoList },
});
이제 화면을 보시면 TodoList가 랜더링 되지 않을것입니다. 그건 namespaced를 설정해서 그런건데 this.$store.state.modulesname...( $store.state.todoList.todoList)으로 적어주셔야 합니다.
// components/HelloWorld.vue
addTodo(text: string) {
this.$store.commit("todoList/addTodo", text); //모듈이름
}
commit같은 경우는 위 처럼 namespaced를 설정해 주어야 합니다.
하지만 너무 깁니다... state를 불러올때도 수정할 때도.. 저희는 이렇게 긴걸 원하지 않습니다.. 조금더 적게 조금더 효율적으로 하고싶습니다. 그때 이용할수 있는것이 Vuex helper를 이용할 수 있습니다.
//HelloWorld.vue
<template>
<el-card class="todo-container">
<h2>Todo List</h2>
<form>
<el-input placeholder="Please input" v-model="input"></el-input>
<el-button type="primary" @click="addTodo(input)">Add Todo</el-button>
</form>
<ul>
<TheListItems />
</ul>
</el-card>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import TheListItems from "./TheListItems.vue";
import { mapState } from "vuex";
interface TodosType {
text?: string;
completed?: boolean;
}
@Component({
components: { TheListItems },
methods: {
...mapMutations({
addTodo: "todoList/addTodo" //this.$store.commit('todoList/addTodo',text)
})
}
})
export default class HelloWorld extends Vue {
input?: string = "";
}
</script>
훨씬 깔끔해 진거 같지 않나요? 더 직관적이기도 하고.
여기서 주의 깊게 보셔야 할 부분이 이 부분 입니다.
@Component({
components: { TheListItems },
methods: {
...mapMutations({
addTodo: "todoList/addTodo" //this.$store.commit('todoList/addTodo',text)
})
}
})
mapMutations의 앞에 ...
은 ES6의 Object Spread Operator입니다.
addTodo라는 변수를 만들어 store에 todoList모듈에 addTodo Mutations를 가져와 선언해주게 됩니다.
어떤가요? 좀더 깔끔한 코드가 된거같지 않나요?
이어 진행해 보겠습니다.
//TheListItems.vue
<template>
<div>
<li
class="todo-item"
v-bind:key="index"
v-for="(todo, index) in todoList"
>
<p class="text">{{ todo.text }}</p>
<el-button v-if="todo.completed" @click="compelete(index)" class="complete completed">Complete</el-button>
<el-button v-else @click="compelete(index)" class="complete">Complete</el-button>
<el-button @click="deleteTodo(index)" class="delete">Delete</el-button>
</li>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { mapState, mapMutations } from "vuex";
@Component({
computed: mapState("todoList", ["todoList"]),//this.$store.todoList.todoList를 등록
methods: {
...mapMutations({
deleteTodo: "deleteTodo/deleteTodo", //this.$store.commit('deleteTodo',text)를 등록
compelete: "todoList/compelete"
})
}
})
export default class extends Vue {}
</script>
<style scoped lang="scss">
.todo-container {
.el-input {
width: 300px;
}
.complete.completed {
background-color: #409eff;
}
}
</style>
어떤가요? MapState를 사용하니 this.$store.todoList.todoList를 todoList로 사용할수 있게 되니 깔끔해 보입니다.
@Component({
computed: mapState("todoList", ["todoList"]),//this.$store.todoList.todoList를 등록
methods: {
...mapMutations({
deleteTodo: "deleteTodo/deleteTodo",
compelete: "todoList/compelete"
})
}
})
여기서 꼭 알고 넘어가야 할점은 mapState와 mapGetters는 computed에, mapMutations와 mapActions는 methods에 입력해 주셔야 합니다.
이번 게시글에서는 Store를 모듈화 하는 법과 Vuex Helper를 사용하여 조금더 코드를 깔끔하게 하는 방법을 배웠습니다.
이 전보다 보기 좋아진거 같지 않나요? 배울수록 깔끔하고 편하게 해주는 기능들이 많은거 같습니다.