[TIL]Vue+Typescirpt+Vuex 사용하기 -5 (Store 모듈화 하기,Vuex helper)

gun·2020년 12월 29일
0

vue+typescript+vuex

목록 보기
5/7
post-thumbnail

Vuex모듈화 하기

크기가 큰 프로젝트를 작업하다 보면 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를 이용할 수 있습니다.


Vuex Hellper

//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를 사용하여 조금더 코드를 깔끔하게 하는 방법을 배웠습니다.
이 전보다 보기 좋아진거 같지 않나요? 배울수록 깔끔하고 편하게 해주는 기능들이 많은거 같습니다.

0개의 댓글