공부방
Vuex응용(TodoList만들기) 본문
프로젝트 생성
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 |