티스토리 뷰

728x90

첫 번째 Todo App을 완성하는데 약 1시간이 걸렸고 vuex를 적용하는 데는 2시간가량이 걸렸다. 주말에 Vue Mastery 사이트에서 전 강좌를 무료로 풀었는데 vuex 강좌를 쭉 들으면서 사용 방법을 익혔다.

 

시작하기 전에 불필요한 Home 관련 코드를 삭제해서 정리한 후 오늘 vuex로 상태를 관리하도록 변경, 컴포넌트를 3개로 나누는 작업을 진행했다. 

 

React.js를 사용할때는 Redux.js를 사용했는데 Vuex.js 사용해 보니 동작 방식은 유사했지만 getters는 차이가 있었다. Redux의 reducer가 vuex에서는 mutations와 같은 역할로 보였다.

 

그리고 컴포넌트에서 사용했던 각각의 옵션과 유사한 기능을 하는 옵션이 store 존재한다. 아래 표는 각 기능을 매핑해 봤다.

Vue Component Vuex Store
data state
methods actions
computed getters

눈여겨 볼만한 부분은 state 변경을 action에서 직접 하지 않고 mutations 함수에서만 변경한다. (redux도 동일)

vuex.vuejs.org/kr

// views/Todo.vue
<template>
  <div class="todo">
    <h1>Todo App</h1>
    <TodoInput />
    <TodoList />
    <TodoFooter />
  </div>
</template>

<script>
import TodoInput from '@/components/TodoInput'
import TodoList from '@/components/TodoList'
import TodoFooter from '@/components/TodoFooter'
export default {
  name: 'Todo',
  components: {
    TodoInput,
    TodoList,
    TodoFooter
  }
}
</script>
// store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    todos: [],
    visibility: 'all',
    selectedTodo: null
  },
  mutations: {
    ADD_TODO(state, todo) {
      state.todos.push(todo)
    },
    REMOVE_TODO(state, id) {
      state.todos = state.todos.filter(todo => todo.id !== id)
    },
    EDIT_TODO(state, text) {
      state.selectedTodo.text = text
      const findIndex = state.todos.findIndex(
        todo => todo.id === state.selectedTodo.id
      )
      state.todos.splice(findIndex, 1, state.selectedTodo)
      state.selectedTodo = null
    },
    REMOVE_COMPLETED_TODO(state) {
      state.todos = state.todos.filter(todo => !todo.completed)
    },
    UPDATE_VISIBILITY(state, visibility) {
      state.visibility = visibility
    },
    SET_EDIT_TODO(state, todo) {
      state.selectedTodo = todo
    }
  },
  actions: {
    createTodo({ commit }, text) {
      commit('ADD_TODO', {
        id: `todo-${Date.now()}`,
        text,
        completed: false
      })
    },
    removeTodo({ commit }, id) {
      commit('REMOVE_TODO', id)
    },
    editTodo({ commit }, text) {
      commit('EDIT_TODO', text)
    },
    removeCompletedTodo({ commit }) {
      commit('REMOVE_COMPLETED_TODO')
    },
    updateVisibility({ commit }, visibility) {
      commit('UPDATE_VISIBILITY', visibility)
    },
    setSelectedTodo({ commit }, todo) {
      commit('SET_EDIT_TODO', todo)
    }
  },
  getters: {
    getFilteredTodos(state) {
      const { visibility } = state
      if (visibility === 'active') {
        return state.todos.filter(todo => !todo.completed)
      } else if (visibility === 'completed') {
        return state.todos.filter(todo => todo.completed)
      } else {
        return state.todos
      }
    },
    completedCount(state) {
      return state.todos.filter(todo => todo.completed).length
    }
  }
})
// TodoList.vue
<template>
  <div>
    <ul>
      <li v-for="todo in getFilteredTodos" :key="todo.id">
        <input type="checkbox" v-model="todo.completed" />
        <span @dblclick="setSelectedTodo(todo)">{{ todo.text }}</span>
        <button type="button" @click="removeTodo(todo.id)">delete</button>
        <input
          type="text"
          @keyup="updateEditTodo"
          v-show="selectedTodo && todo.id === selectedTodo.id"
        />
      </li>
    </ul>
  </div>
</template>

<script>
import { mapGetters, mapActions, mapState } from 'vuex'
export default {
  name: 'TodoList',
  methods: {
    updateEditTodo(event) {
      if (event.code === 'Enter') {
        this.editTodo(event.currentTarget.value)
      }
    },
    ...mapActions(['setSelectedTodo', 'editTodo', 'removeTodo'])
  },
  computed: {
    ...mapGetters(['getFilteredTodos']),
    ...mapState(['selectedTodo'])
  }
}
</script>

vuex에서 각 옵션이 설정한 값을 쉽게 가져다 쓸 수 있도록 mapXX 함수를 제공하고 있다. 앞선 컴포넌트 예제에서 보듯 쉽게 가져다가 쓸 수 있어서 코드가 간결해진다. 최종 코드는 이 저장소에서 확인 할 수 있다.

 

 

728x90
댓글