본문 바로가기
Vue

[vue] todo-list 생성 - vuex

by nozee 2021. 11. 21.
반응형
본 포스팅은 인프런의 캡틴판교님의 Vue.js 중급 강의를 기반으로 만들어졌습니다.


개요

이전에 todo-list 작성했던 부분은 $emit과 props를 이용해서 만들었었다.

이번에는 이전에 만들었던 todo-list를 vuex를 통해 리펙토링을 진행하였다.

 

2021.11.11 - [Vue] - [vue] todo-list 생성

 

[vue] todo-list 생성

본 포스팅은 인프런의 캡틴판교님의 Vue.js 중급 강의를 기반으로 만들어졌습니다. 개요 회사에서 뷰를 사용하기 시작하여 뷰 강의를 듣기 시작하였고 인프런 캡틴판교님의 강의가 유명하다고

nozee.tistory.com

 

 

 

Vuex 설치

 

  • vuex 설치
npm install vuex

 

 

 

vuex 라이브러리가 추가된 것을 확인할 수 있다.

 

 

개발 소스

 

 

  • 파일 구성

 

기존 소스와 비교하면 vuex 소스를 담는 store 부분을 추가하였다.

 

 

  • store.js
import Vue from 'vue'
import Vuex from 'vuex'


Vue.use(Vuex);

const storage = {
    initTodo() {
        const arr = []
        for(var i = 0 ; i < localStorage.length ; i++){
            if(localStorage.key(i) != 'loglevel:webpack-dev-server'){
              arr.push(JSON.parse(localStorage.getItem(localStorage.key(i))))
            }
        }
        return arr
    }
}


export const store = new Vuex.Store({
    state: {
        todos: storage.initTodo()
    },
    getters : {
        storedTodoItems(state){
            return state.todos;
        }
    },
    mutations: {
        addTodoItem(state,newTodoItem){
            let item = {
                str : newTodoItem,
                done : false
            }
            localStorage.setItem(newTodoItem, JSON.stringify(item))
            state.todos.push(item)
        },
        clearAllItems(state){
            localStorage.clear()
            state.todos = []
        },
        removeTodo(state, str, index){
            state.todos.splice(index, 1)
            localStorage.removeItem(str)
        },
        completeTodo(state, modifyTodo, index){
            state.todos[index].done = !this.todos[index].done
            localStorage.removeItem(modifyTodo.str)
            localStorage.setItem(modifyTodo.str, JSON.stringify(this.todos[index]))
        }
    },
    actions: {

    }
})

 

store.js에서는 기존에 App.vue에서 사용했던 data를 state로 가져오고 methods를 mutations으로 가져와 선언을 해주었다. 

 

  • main.js
import Vue from 'vue'
import App from './App.vue'
import { store } from './store/stores'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

 

main.js 에 새로 생성된 store를 선언해 주어 소스 전체에서 vuex에 접근할 수 있도록 해준다.

 

 

 

  • App.vue
<template>
  <div id="app">
    <TodoHeader></TodoHeader>
    <TodoInput></TodoInput>
    <TodoList></TodoList>
    <TodoFooter></TodoFooter>
  </div>
</template>

<script>
import TodoHeader from './components/TodoHeader.vue'
import TodoInput from './components/TodoInput.vue'
import TodoList from './components/TodoList.vue'
import TodoFooter from './components/TodoFooter.vue'
export default {
  components : {
    TodoHeader,
    TodoInput,
    TodoList,
    TodoFooter
  }
}
</script>

<style>
body {
  text-align: center;
  background-color : #f6f6f6;
}
input {
  border-style : groove;
  width: 200px;
}
button {
  border-style : groove;
}
.shadow {
  box-shadow: 5px 10px 10px rgba(0,0,0,0.03);
}
</style>

 

App.vue에서 data, methods부분은 store 부분에 선언을 해주었기 때문에 제거하여 준다.

또한 component들에 기존 props와 $emit으로 연결되어 있던 부분들도 제거하여 준다.

 

 

 

  • TodoInput.vue
<template>
  <div class="inputBox shadow">
    <input type="text" v-model="newTodoItem" @keypress.enter="addTodo">
    <span class="addContainer" @click="addTodo">
        <i class="fas fa-plus addBtn"></i>
    </span>
  </div>
</template>

<script>
export default {
    data() {
        return {
            newTodoItem : ""
        }
    },
    methods: {
        addTodo(){
            if(this.newTodoItem == ""){
                alert('입력된 값이 없습니다.')
            }else{
                this.$store.commit('addTodoItem', this.newTodoItem)
                this.newTodoItem = "" 
            }
        }
    }
}
</script>

<style scoped>
input:focus {
  outline: none;
}
.inputBox {
  background: white;
  height: 50px;
  line-height: 50px;
  border-radius: 5px;
}
.inputBox input {
  border-style: none;
  font-size: 0.9rem;
}
.addContainer {
  float: right;
  background: linear-gradient(to right, #6478FB, #8763FB);
  display: block;
  width: 3rem;
  border-radius: 0 5px 5px 0;
}
.addBtn {
  cursor: pointer;
  color: white;
  vertical-align: middle;
}
.closeModalBtn {
  color: #42b983;
}
</style>

TodoInput.vue에서는 기존 addTodo 했던 부분이 $emit으로 App.vue에 있는 addTodoItem을 호출하도록 되어 있었다.

addTodoItem이 store.js로 갔기 때문에 mutations에 선언된 addTodoItem이 호출되도록 변경하였다. 

vuex에서 mutations에 선언된 메서드를 호출하기 위해서는 commit 명령어를 사용해서 호출을 한다.

 

 

 

  • TodoList.vue
<template>
  <ul>
    <li v-for="(todo, index) in this.storedTodoItems" :key=todo.str>
        <i class="checkBtn fas fa-check" :class="{checkBtnCompleted: todo.done}"
            @click="toggleComplete({todo, index})"></i>
        <span :class="{textCompleted: todo.done}">{{todo.str}} </span>
        <span class="removeBtn" v-on:click="removeTodo({todo, index})">
          <i class="fas fa-trash-alt"></i>
        </span>
    </li>
  </ul>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex'

export default {

    methods: {
      ...mapMutations(['removeTodo','toggleComplete'] )
    },
    computed : {
      ...mapGetters(['storedTodoItems'])
    }

}
</script>

<style scoped>
ul {
  list-style-type: none;
  padding-left: 0px;
  margin-top: 0;
  text-align: left;
}
li {
  display: flex;
  min-height: 50;
  height: 50px;
  line-height : 50px;
  margin: 0.5rem 0;
  padding: 0 0.9rem;
  background: white;
  border-radius: 5px;
}
.checkBtn {
  line-height: 45px;
  color: #62acde;
  margin-right: 5px;
}
.removeBtn {
  margin-left: auto;
  color : #de4343;
}
.checkBtnCompleted {
color : #b3adad;
}
.textCompleted {
  text-decoration: line-through;
  color: #b3adad;
}
/* 리스트 아이템 트랜지션 효과 */
.list-enter-active, .list-leave-active {
  transition: all 1s;
}
.list-enter, list-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
</style>

TodoList에서는 기존에 props로 받았던 todo를 store.js에 있는 getters 통해 storedTodoItems로 받도록 변경하였다.

removeTodo, toggleComplete도 마찬가지로 mutations에 있는 메서드가 호출되도록 변경하였다.

 

vuex를 import 해주게 되면 mapState, mapGetters, mapMutations, mapActions를 접근할 수 있게 된다.

es6에서 제공하는 전개 연산자와 같이 사용하면 위에 소스와 같은 형태로 vuex에 접근할 수 있게 된다.

 

 

 

 

  • TodoFooter.vue
<template>
  <div class="clearAllContainer">
    <span class="clearAllBtn" @click="clearAllItems">Clear All</span>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations(['clearAllItems'])
  },
}
</script>

<style>
.clearAllContainer {
  width: 8.5rem;
  height: 50px;
  line-height: 50px;
  background-color: white;
  border-radius: 5px;
  margin: 0 auto;
}
.clearAllBtn {
  cursor: pointer;
  color: #e20303;
  display: block;
}
</style>

TodoFooter.vue도 TodoList.vue와 마찬가지로 vuex를 import 하여 mapMutations를 가져왔고 mapMutations에 clearAllItems를 가져오도록 하였다.

 

 

개발 화면

 

 

 

 

 

 

본 포스팅은 여기까지 입니다.
읽어주셔서 감사합니다.




반응형

'Vue' 카테고리의 다른 글

[vue] todo-list 생성  (0) 2021.11.11