공부방

Vuex응용(TodoList만들기) 본문

vue.js

Vuex응용(TodoList만들기)

코딩 화이팅 2023. 5. 12. 14:33

프로젝트 생성

vue create vue-todo-app->cd로 들어가기->vue add vuex

브라우저 화면에 띄우기

App.vue
<template>
  <div id="app">
    <h2>우리의 할일</h2>
    <todo-write></todo-write>
    <hr />
    <todo-list></todo-list>
  </div>
</template>

<script>
// import를 하자

import TodoList from "@/components/TodoList.vue";
import TodoWrite from "./components/TodoWrite.vue";

export default {
  name: "App",
  components: {
    TodoList,
    TodoWrite,
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
=============================================================
TodoWrite.vue
<template>
  <div>
    <h2>할일 작성</h2>    
  </div>
</template>

<script>
export default {
  name: "TodoWrite",
};
</script>

<style></style>
=============================================================
TodoList.vue
<template>
  <div>
    <h2>할일 목록</h2>
  </div>
</template>

<script>

export default {
  name: "TodoList",
};
</script>

<style></style>

글 등록

Write(dispatch를 사용하여)->Vuex(Actions)(commit으로)->mutation->state

TodoWrite.vue
<template>
  <div>
    <h2>할일 작성</h2>
    <input
      type="text"
      v-model.trim="work"
      @keyup.enter="createTodo"
      ref="todoInput"
    />
    <!-- trim은 알아서 공백을 제거를 해줄 수 있다 -->
    <button @click="createTodo">등록</button>
  </div>
</template>

<script>
export default {
  name: "TodoWrite",
  data() {
    return {
      work: "",
    };
  },
  methods: {
    createTodo() {
      const todoItem = {
        work: this.work,
        done: false,
      };

      //유효성 검사 (아무것도 적지 않았으면 하지마~~)
      if (this.work) {
        this.$store.dispatch("createTodo", todoItem);
        // 박스 안에 내용을 비워주기
        this.work = "";
      } else {
        //공백이라서 등록 못해~~~ 포커싱을 다시 input태그로 옮겨보자~~
        alert("내용 입력해주세요 제발료~~");
        //인스턴스가 참조하고 있는 목록 전체 가져오기
        this.$refs.todoInput.focus();
      }
    },
  },
};
</script>

<style></style>
================================================================
index.js
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

export default new Vuex.Store({
  plugins: [createPersistedState()],
  state: {
    //전체 할일을 요기서 관리하련다~~
    todos: [],
  },
  getters: {
  },
  mutations: {
    CREATE_TODO(state, todoItem) {
      state.todos.push(todoItem);
    },
  },
  actions: {
    createTodo({ commit }, payload) {
      commit("CREATE_TODO", payload);
    },
  },
  modules: {},
});

로컬 스토리지 사용해서 데이터 넣기

npm사이트->@cojecom/vuex-persistedstate 검색해서 터미널에

$ npm install vuex-persistedstate

입력

나머지 코드는 위와 동일
index.js
import Vue from "vue";
import Vuex from "vuex";
//로컬 스토리지를 쓰기 위한 import
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

export default new Vuex.Store({
  // 로컬 스토리지를 위해
  plugins: [createPersistedState()],
  state: {
    //전체 할일을 요기서 관리하련다~~
    todos: [],
  },
  getters: {
  },
  mutations: {
    //등록 신나게 해놨는데 새로고침하거나... 껐다 키거나... 코드 수정이 들어가면 자꾸 날아간다.
    //그러한 것을 방지하기 위해서 로컬스토리지라고 하는것을 썼었다.!!!!
    CREATE_TODO(state, todoItem) {
      state.todos.push(todoItem);
    },
  },
  actions: {
    createTodo({ commit }, payload) {
      commit("CREATE_TODO", payload);
    },
  },
  modules: {},
});

목록을 써보기

TodoList.vue
<template>
  <div>
    <h2>할일 목록</h2>
    <todo-list-item
      v-for="(todo, index) in todos"
      :key="index"
      :todoItem="todo"
    >
      <!-- :todoItem="todo" -->
      <!-- todoItem이라는 걸 TodoListItem에 내려보내겠다.
      todo라는 이름으로 -->
    </todo-list-item>
  </div>
</template>

<script>
//이렇게 헬퍼써도 같다.
import { mapState } from "vuex";
import TodoListItem from "./TodoListItem.vue";

export default {
  name: "TodoList",
  components: {
    TodoListItem,
  },
  computed: {
    todos() {
      return this.$store.state.todos;
    },
    //헬퍼
    ...mapState(["todos"]),
  },
};
</script>

<style></style>
===============================================================
TodoListItem.vue
<template>
  <div>
    <!-- 클래스 바인딩 -->
    <span>{{ todoItem.work }}</span>
  </div>
</template>

<script>
export default {
  name: "TodoListItem",
  props: {
    todoItem: Object,
  },
  // TodoList에서 받은 todoItem을 props로 받음
  methods: {
  },
};
</script>

<style scoped>
.is-done {
  text-decoration: line-through;
  color: red;
}
.click-cursor {
  cursor: pointer;
}
</style>

 각 목록들을 눌렀을 때 빨간 줄을 쳐주기

TodoListItem.vue
<template>
  <div>
    <!-- 클래스 바인딩 -->
    <span @click="updateTodo(todoItem)">{{ todoItem.work }}</span>
    <!-- 이 단어를 클릭하면 빨간줄이 나오게 만들고 싶다. -->
  </div>
</template>

<script>
// import { mapActions } from 'vuex';
export default {
  name: "TodoListItem",
  props: {
    todoItem: Object,
  },
  // TodoList에서 받은 todoItem을 props로 받음
  methods: {
    //빨간 줄이 나오게 하려면 todoItem값을 바꿔야되는데 todoItem은
    // 부모한테 받은 데이터이기 때문에 함부로 바꿀 수 없다. 그러므로
    // vuex에게 말을 해봐야한다.
    updateTodo() {
      // 그냥 보내면 뭐를 바꿔달라는 지 모르기 때문에
      // this.todoItem라는 객체를 같이 보낸다.
      this.$store.dispatch("updateTodo", this.todoItem);
    },
  },
};
</script>

<style scoped>
.is-done {
  text-decoration: line-through;
  color: red;
}
.click-cursor {
  cursor: pointer;
}
</style>
=============================================================
index.js
import Vue from "vue";
import Vuex from "vuex";
//로컬 스토리지를 쓰기 위한 import
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

export default new Vuex.Store({
  // 로컬 스토리지를 위해
  plugins: [createPersistedState()],
  state: {
    //전체 할일을 요기서 관리하련다~~
    todos: [],
  },
  getters: {
  },
  mutations: {
    //등록 신나게 해놨는데 새로고침하거나... 껐다 키거나... 코드 수정이 들어가면 자꾸 날아간다.
    //그러한 것을 방지하기 위해서 로컬스토리지라고 하는것을 썼었다.!!!!
    CREATE_TODO(state, todoItem) {
      state.todos.push(todoItem);
    },
    UPDATE_TODO(state, todoItem) {
      const idx = state.todos.indexOf(todoItem);
      state.todos[idx].done = !state.todos[idx].done;
      // done값을 반대로 해주겠다
    },
  },
  actions: {
    createTodo({ commit }, payload) {
      commit("CREATE_TODO", payload);
    },
    updateTodo({ commit }, payload) {
      commit("UPDATE_TODO", payload);
    },
  },
  modules: {},
});

이제 글자들을 눌러주면 done값이 false에서 true로 바뀐다.

나머지 코드는 위와 동일
TodoListItem.vue
<template>
  <div>
    <!-- 클래스 바인딩 -->
    <span
      @click="updateTodo(todoItem)"
      class="click-cursor"
      :class="{ 'is-done': todoItem.done }"
      >{{ todoItem.work }}</span
    >
    <!-- class="click-cursor" : 포인터가 글자 위로 가면 바뀐다. -->
    <!-- :class="{ 'is-done': todoItem.done } : todoItem.done이 true면 클래스를 쓰고
    false면 쓰지 않는다. -->
    <!-- 이 단어를 클릭하면 빨간줄이 나오게 만들고 싶다. -->
  </div>
</template>

<script>
// import { mapActions } from 'vuex';
export default {
  name: "TodoListItem",
  props: {
    todoItem: Object,
  },
  // TodoList에서 받은 todoItem을 props로 받음
  methods: {
    //빨간 줄이 나오게 하려면 todoItem값을 바꿔야되는데 todoItem은
    // 부모한테 받은 데이터이기 때문에 함부로 바꿀 수 없다. 그러므로
    // vuex에게 말을 해봐야한다.
    updateTodo() {
      // 그냥 보내면 뭐를 바꿔달라는 지 모르기 때문에
      // this.todoItem라는 객체를 같이 보낸다.
      this.$store.dispatch("updateTodo", this.todoItem);
    },
    // deleteTodo() {
    //   this.$store.dispatch('deleteTodo', this.todoItem);
    // },
    // ...mapActions(['updateTodo', 'deleteTodo']),
  },
};
</script>

<style scoped>
.is-done {
  text-decoration: line-through;
  color: red;
}
.click-cursor {
  cursor: pointer;
}
</style>

투두 삭제하기

TodoListItem.vue
<template>
  <div>
    <!-- 클래스 바인딩 -->
    <span
      @click="updateTodo(todoItem)"
      class="click-cursor"
      :class="{ 'is-done': todoItem.done }"
      >{{ todoItem.work }}</span
    >
    <button @click="deleteTodo(todoItem)">삭제</button>
    <!-- class="click-cursor" : 포인터가 글자 위로 가면 바뀐다. -->
    <!-- :class="{ 'is-done': todoItem.done } : todoItem.done이 true면 클래스를 쓰고
    false면 쓰지 않는다. -->
    <!-- 이 단어를 클릭하면 빨간줄이 나오게 만들고 싶다. -->
  </div>
</template>

<script>
//헬퍼 이렇게 사용 가능
import { mapActions } from "vuex";
export default {
  name: "TodoListItem",
  props: {
    todoItem: Object,
  },
  // TodoList에서 받은 todoItem을 props로 받음
  methods: {
    //빨간 줄이 나오게 하려면 todoItem값을 바꿔야되는데 todoItem은
    // 부모한테 받은 데이터이기 때문에 함부로 바꿀 수 없다. 그러므로
    // vuex에게 말을 해봐야한다.
    updateTodo() {
      // 그냥 보내면 뭐를 바꿔달라는 지 모르기 때문에
      // this.todoItem라는 객체를 같이 보낸다.
      this.$store.dispatch("updateTodo", this.todoItem);
    },
    deleteTodo() {
      this.$store.dispatch("deleteTodo", this.todoItem);
    },
    //헬퍼 이렇게 사용 가능
    // 그대신 template에 deleteTodo옆에 todoItem을 넣어줘야된다.
    ...mapActions(["updateTodo", "deleteTodo"]),
  },
};
</script>

<style scoped>
.is-done {
  text-decoration: line-through;
  color: red;
}
.click-cursor {
  cursor: pointer;
}
</style>
================================================================
index.js
import Vue from "vue";
import Vuex from "vuex";
//로컬 스토리지를 쓰기 위한 import
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

export default new Vuex.Store({
  // 로컬 스토리지를 위해
  plugins: [createPersistedState()],
  state: {
    //전체 할일을 요기서 관리하련다~~
    todos: [],
  },
  getters: {
  },
  mutations: {
    //등록 신나게 해놨는데 새로고침하거나... 껐다 키거나... 코드 수정이 들어가면 자꾸 날아간다.
    //그러한 것을 방지하기 위해서 로컬스토리지라고 하는것을 썼었다.!!!!
    CREATE_TODO(state, todoItem) {
      state.todos.push(todoItem);
    },
    UPDATE_TODO(state, todoItem) {
      const idx = state.todos.indexOf(todoItem);
      state.todos[idx].done = !state.todos[idx].done;
      // done값을 반대로 해주겠다
    },
    DELETE_TODO(state, todoItem) {
      const idx = state.todos.indexOf(todoItem);
      state.todos.splice(idx, 1);
    },
  },
  actions: {
    createTodo({ commit }, payload) {
      commit("CREATE_TODO", payload);
    },
    updateTodo({ commit }, payload) {
      commit("UPDATE_TODO", payload);
    },
    deleteTodo({ commit }, payload) {
      if (confirm("정말로 지울거니?")) {
        // confirm : 알림창을 한 번 나오게 한다
        commit("DELETE_TODO", payload);
      }
    },
  },
  modules: {},
});

확인을 누르면 지워지고 취소를 누르면 지워지지 않는다.

Gettes를 사용하여 완료, 미완료 리스트를 세기

App.vue
<template>
  <div id="app">
    <h2>우리의 할일</h2>
    <!-- state에 todos를 통해 알아낼 수 있다 -->
    <h4>전체 Todo : {{ allCount }}</h4>
    <h4>완료 Todo : {{ doneCount }}</h4>
    <!-- 이렇게 해도 되고 -->
    <h4>미완료 Todo : {{ undoneCount }}</h4>
    <!-- 이렇게 해도 됨 -->
    <h4>미완료 Todo : {{ allCount - doneCount }}</h4>
    <todo-write></todo-write>
    <hr />
    <todo-list></todo-list>
  </div>
</template>

<script>
// import를 하자
// import { mapGetters } from "vuex";

import TodoList from "@/components/TodoList.vue";
import TodoWrite from "./components/TodoWrite.vue";

export default {
  name: "App",
  components: {
    TodoList,
    TodoWrite,
  },
  computed: {
    allCount() {
      return this.$store.state.todos.length;
    },
    doneCount() {
      return this.$store.getters.doneCount;
    },
    undoneCount() {
      return this.$store.getters.undoneCount;
    },
    // 헬퍼를 쓸 때 메서드 이름이 다르면 이렇게 객체처럼 넣어서 사용할 수 있다
    // ...mapGetters({
    //   doneCount: "doneCount2",
    // }),
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
===============================================================
index.js
import Vue from "vue";
import Vuex from "vuex";
//로컬 스토리지를 쓰기 위한 import
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

export default new Vuex.Store({
  // 로컬 스토리지를 위해
  plugins: [createPersistedState()],
  state: {
    //전체 할일을 요기서 관리하련다~~
    todos: [],
  },
  getters: {
    doneCount(state) {
      let cnt = 0;
      for (let i = 0; i < state.todos.length; i++) {
        if (state.todos[i].done) {
          cnt++;
        }
      }
      return cnt;
    },
    // 이렇게 간단하게 작성할 수도 있다.
    // doneCount2(state){
    //   return state.todos.filter(todo => todo.done).length
    // },
    undoneCount(state) {
      let cnt = 0;
      for (let i = 0; i < state.todos.length; i++) {
        if (!state.todos[i].done) {
          cnt++;
        }
      }
      return cnt;
    },
  },
  mutations: {
    //등록 신나게 해놨는데 새로고침하거나... 껐다 키거나... 코드 수정이 들어가면 자꾸 날아간다.
    //그러한 것을 방지하기 위해서 로컬스토리지라고 하는것을 썼었다.!!!!
    CREATE_TODO(state, todoItem) {
      state.todos.push(todoItem);
    },
    UPDATE_TODO(state, todoItem) {
      const idx = state.todos.indexOf(todoItem);
      state.todos[idx].done = !state.todos[idx].done;
      // done값을 반대로 해주겠다
    },
    DELETE_TODO(state, todoItem) {
      const idx = state.todos.indexOf(todoItem);
      state.todos.splice(idx, 1);
    },
  },
  actions: {
    createTodo({ commit }, payload) {
      commit("CREATE_TODO", payload);
    },
    updateTodo({ commit }, payload) {
      commit("UPDATE_TODO", payload);
    },
    deleteTodo({ commit }, payload) {
      if (confirm("정말로 지울거니?")) {
        // confirm : 알림창을 한 번 나오게 한다
        commit("DELETE_TODO", payload);
      }
    },
  },
  modules: {},
});

 

'vue.js' 카테고리의 다른 글

axios응용  (0) 2023.05.12
Vuex  (0) 2023.05.11
Vue Style Guide  (0) 2023.05.10
Vue Axios  (0) 2023.05.10
Vue Router  (0) 2023.05.09