Todo
์ฌ์ ์ค๋น
ํ๋ก์ ํธ ๊ฐ์
- ํ๋ก์ ํธ ์์ฑ ๋ฐ vuex ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
$ vue create todo-vuex-app
$ cd todo-vuex-app
$ vue add vuex
- HelloWorld ์ปดํฌ๋ํธ ๋ฐ ๊ด๋ จ ์ฝ๋ ์ญ์
์ปดํฌ๋ํธ ์์ฑ
// components/TodoListItem.vue
<template>
<div>Todo</div>
</template>
<script>
export default {
name: "TodoListItem",
};
</script>
<style></style>
// components/TodoList.vue
<template>
<div>
<TodoListItem />
</div>
</template>
<script>
import TodoListItem from "./TodoListItem.vue";
export default {
name: "TodoList",
components: {
TodoListItem,
},
};
</script>
<style></style>
// components/TodoForm.vue
<template>
<div>Todo Form</div>
</template>
<script>
export default {
name: "TodoForm",
};
</script>
<style></style>
// App.vue
<template>
<div id="app">
<h1>Todo List</h1>
<TodoList />
<TodoForm />
</div>
</template>
<script>
import TodoForm from "./components/TodoForm.vue";
import TodoList from "./components/TodoList.vue";
export default {
name: "App",
components: {
TodoList,
TodoForm,
},
};
</script>
ํ์ด์ง ํ์ธ
![](https://blog.kakaocdn.net/dn/cWlCYw/btrQC810HwP/eZWl4a0LL8dj8FPjBSoE30/img.png)
Read Todo
State ์ธํ
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todos: [
{
title: 'ํ ์ผ 1',
isCompleted: false,
},
{
title: 'ํ ์ผ 2',
isCompleted: false,
}
]
},
...
})
state ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
// components/TodoList.vue
<template>
<div>
<TodoListItem v-for="(todo, index) in todos" :key="index" :todo="todo" />
</div>
</template>
<script>
import TodoListItem from "./TodoListItem.vue";
export default {
name: "TodoList",
components: {
TodoListItem,
},
computed: {
todos() {
return this.$store.state.todos;
},
},
};
</script>
<style></style>
Pass Props
// components/TodoListItem.vue
<template>
<div>{{ todo.title }}</div>
</template>
<script>
export default {
name: "TodoListItem",
props: {
todo: Object,
},
};
</script>
<style></style>
![](https://blog.kakaocdn.net/dn/cmU8ni/btrQIuhTcOg/DOlCA5vJ5Mle7G5tAELdvK/img.png)
Create Todo
TodoForm, Actions
// components/TodoForm.vue
<template>
<div>
<input type="text" v-model="todoTitle" @keyup.enter="createTodo" />
</div>
</template>
<script>
export default {
name: "TodoForm",
data() {
return {
todoTitle: null,
};
},
methods: {
createTodo() {
// console.log(this.todoTitle)
this.$store.dispatch("createTodo", this.todoTitle);
this.todoTitle = null;
},
},
};
</script>
โ todoTitle์ ์
๋ ฅ ๋ฐ์ input ํ๊ทธ ์์ฑ
โ todoTitle์ ์ ์ฅํ๊ธฐ ์ํด data๋ฅผ ์ ์ํ๊ณ input๊ณผ v-model์ ์ด์ฉํด ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ
โ enter ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํด createTodo ๋ฉ์๋ ์ถ๋ ฅ ํ์ธ
โ createTodo ๋ฉ์๋์์ actions๋ฅผ ํธ์ถ(dispatch)
Mutations
// index.js
export default new Vuex.Store({
...
actions: {
createTodo(context, todoTitle) {
// Todo ๊ฐ์ฒด ๋ง๋ค๊ธฐ
const todoItem = {
title: todoTitle,
isCompleted: false,
};
// console.log(todoItem)
context.commit('CREATE_TODO', todoItem)
},
},
modules: {},
});
โ CREATE_TODO mutations ๋ฉ์๋์ todoItem์ ์ ๋ฌํ๋ฉฐ ํธ์ถ(commit)
// index.js
export default new Vuex.Store({
...
mutations: {
CREATE_TODO(state, todoItem) {
state.todos.push(todoItem)
}
},
...
});
โ mutations์์ state์ todos์ ์ ๊ทผํด ๋ฐฐ์ด์ ์์ ์ถ๊ฐ
export default new Vuex.Store({
state: {
todos: [],
},
...
})
โ ๊ธฐ์กด dummy data ์ญ์
์ค๊ฐ ์ ๋ฆฌ!
โ Vue ์ปดํฌ๋ํธ์ method์์ dispatch๋ฅผ ์ฌ์ฉํด actions ๋ฉ์๋ ํธ์ถ
โ Actions์ ์ ์๋ ํจ์๋ commit()๋ฅผ ์ฌ์ฉํด mutations ํธ์ถ
โ Mutations์ ์ ์๋ ํจ์๊ฐ ์ต์ข
์ ์ผ๋ก state ๋ณ๊ฒฝ
Delete Todo
TodoListItem
// components/TodoListItem.vue
<template>
<div>
{{ todo.title }}
<button @click="deleteTodo">Delete</button>
</div>
</template>
<script>
export default {
name: "TodoListItem",
props: {
todo: Object,
},
method: {
deleteTodo() {
this.$store.dispatch("deleteTodo");
},
},
};
</script>
โ TodoListItem ์ปดํฌ๋ํธ์ ์ญ์ ๋ฒํผ ๋ฐ deleteTodo ๋ฉ์๋ ์์ฑ
Actions
export default new Vuex.Store({
...
actions: {
createTodo(context, todoTitle) {
// Todo ๊ฐ์ฒด ๋ง๋ค๊ธฐ
const todoItem = {
title: todoTitle,
isCompleted: false,
};
// console.log(todoItem)
context.commit('CREATE_TODO', todoItem)
},
// ์ด ๊ฒฝ์ฐ๋ ์๋ตํ๊ณ ๋ฐ๋ก mutations ํธ์ถ ๊ฐ๋ฅ
deleteTodo(context, todoItem) {
context.commit('DELETE_TODO', todoItem)
},
},
modules: {},
});
โ ์ด ๊ฒฝ์ฐ๋ ๋ฐ๋ก ๊ธฐ๋ฅ์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก mutations๋ก ํธ์ถ์ด ๊ฐ๋ฅํ๋ค
Mutations
export default new Vuex.Store({
...
mutations: {
CREATE_TODO(state, todoItem) {
state.todos.push(todoItem)
},
DELETE_TODO(state, todoItem) {
const index = state.todos.indexOf(todoItem)
state.todos.splice(index, 1)
}
},
})
โ ์ ๋ฌ๋ ๋ todoItem์ ํด๋นํ๋ todo ์ญ์
Update Todo
TodoListItem
// components/TodoListItem.vue
<template>
<div>
<span @click="updateTodoStatus">
{{ todo.title }}
</span>
<button @click="deleteTodo">Delete</button>
</div>
</template>
<script>
export default {
name: 'TodoListItem',
props: {
todo: Object,
},
methods: {
...
updateTodoStatus() {
this.$store.dispatch('updateTodoStatus', this.todo)
}
},
}
</script>
Actions
// index.js
export default new Vuex.Store({
...
actions: {
...
updateTodoStatus(context, todoItem) {
context.commit('UPDATE_TODO_STATUS', todoItem)
}
},
modules: {},
});
Mutations
export default new Vuex.Store({
...
mutations: {
...
UPDATE_TODO_STATUS(state, todoItem) {
// console.log(todoItem)
state.todos = state.todos.map((todo) => {
if (todo === todoItem) {
todo.isCompleted = !todo.isCompleted
}
return todo
})
}
},
...
});
โ map ๋ฉ์๋ ํ์ฉํด ์ ํ๋ todo์ isCompleted๋ฅผ ๋ฐ๋๋ก ๋ณ๊ฒฝ ํ ๊ธฐ์กด ๋ฐฐ์ด ์ ๋ฐ์ดํธ
์ทจ์์ ์คํ์ผ๋ง
// components/TodoListItem.vue
<template>
<div>
<span
@click="updateTodoStatus"
:class="{ 'is-completed' : todo.isCompleted }"
>
{{ todo.title }}
</span>
<button @click="deleteTodo">Delete</button>
</div>
</template>
<script>
export default {
name: 'TodoListItem',
props: {
todo: Object,
},
methods: {
deleteTodo() {
this.$store.dispatch('deleteTodo', this.todo)
},
updateTodoStatus() {
this.$store.dispatch('updateTodoStatus', this.todo)
}
},
}
</script>
<style>
.is-completed {
text-decoration: line-through;
}
</style>
โ CSS ์์ฑ ํ v-bind ํ์ฉํด isCompleted ๊ฐ์ ๋ฐ๋ผ css ํด๋์ค๊ฐ ํ ๊ธ ๋ฐฉ์์ผ๋ก ์ ์ฉ๋๋๋ก ์์ฑ
๋์ ํ์ธ
![](https://blog.kakaocdn.net/dn/WiGYQ/btrQD9TmABW/sAGp9NMQi0ZSLCIx0ZhLLK/img.png)
์ํ๋ณ todo ๊ฐ์ ๊ณ์ฐ
์ ์ฒด todo ๊ฐ์
export default new Vuex.Store({
state: {
todos: [],
},
getters: {
allTodosCount(state) {
return state.todos.length
}
},
...
})
โ allTodosCount
getters ์์ฑ
โ state์ ์๋ todos ๋ฐฐ์ด์ ๊ธธ์ด ๊ณ์ฐ
// App.vue
<template>
<div id="app">
<h1>Todo List</h1>
<h2>All Todos: {{ allTodosCount }}</h2>
<TodoList/>
<TodoForm/>
</div>
</template>
<script>
import TodoForm from './components/TodoForm.vue'
import TodoList from './components/TodoList.vue'
export default {
name: 'App',
components: {
TodoList,
TodoForm
},
computed: {
allTodosCount() {
return this.$$store.getters.allTodosCount
}
},
}
</script>
โ getters์ ๊ณ์ฐ๋ ๊ฐ์ ๊ฐ ์ปดํฌ๋ํธ์ computed์์ ์ฌ์ฉํ๊ธฐ
์๋ฃ๋ todo ๊ฐ์
// index.js
export default new Vuex.Store({
state: {
todos: [],
},
getters: {
allTodosCount(state) {
return state.todos.length
},
completedTodosCount(state) {
// 1. ์๋ฃ๋ todo๋ง ๋ชจ์ ๋์ ์๋ก์ด ๊ฐ์ฒด ์์ฑ
const completedTodos = state.todos.filter((todo) => {
return todo.isCompleted == true
})
// 2. ๊ธธ์ด ๋ฐํ
return completedTodos.length
},
},
}
โ completedTodosCount
getters ์์ฑ
โ isCompleted๊ฐ true ์ธ todo๋ค๋ง ํํฐ๋งํ ๋ฐฐ์ด์ ๋ง๋ค๊ณ ๊ธธ์ด ๊ณ์ฐ
// App.vue
<template>
<div id="app">
<h1>Todo List</h1>
<h2>All Todos: {{ allTodosCount }}</h2>
<h2>Completed Todo: {{ completedTodosCount }}</h2>
<TodoList/>
<TodoForm/>
</div>
</template>
<script>
import TodoForm from './components/TodoForm.vue'
import TodoList from './components/TodoList.vue'
export default {
name: 'App',
components: {
TodoList,
TodoForm
},
computed: {
allTodosCount() {
return this.$store.getters.allTodosCount
},
completedTodosCount() {
return this.$store.getters.completedTodosCount
}
},
}
</script>
๋ฏธ์๋ฃ๋ todo ๊ฐ์
// index.js
export default new Vuex.Store({
state: {
todos: [],
},
getters: {
...
unCompletedTodosCount(state, getters) {
return getters.allTodosCount - getters.completedTodosCount
}
},
})
โ ๋ฏธ์๋ฃ๋ todo ๊ฐ์ === ์ ์ฒด ๊ฐ์ - ์๋ฃ ๊ฐ์
โ getters ๊ฐ ๋๋ฒ์งธ ์ธ์๋ก getters ๋ฐ๋ ๊ฒ ํ์ฉ
// App.vue
<template>
<div id="app">
<h1>Todo List</h1>
<h2>All Todos: {{ allTodosCount }}</h2>
<h2>Completed Todo: {{ completedTodosCount }}</h2>
<h2>unCompleted Todo: {{ unCompletedTodosCount }}</h2>
<TodoList/>
<TodoForm/>
</div>
</template>
<script>
import TodoForm from './components/TodoForm.vue'
import TodoList from './components/TodoList.vue'
export default {
name: 'App',
components: {
TodoList,
TodoForm
},
computed: {
allTodosCount() {
return this.$store.getters.allTodosCount
},
completedTodosCount() {
return this.$store.getters.completedTodosCount
},
unCompletedTodosCount() {
return this.$store.getters.unCompletedTodosCount
}
},
}
</script>
๋์ ํ์ธ
![](https://blog.kakaocdn.net/dn/bSkLte/btrQDEzfks2/eXoTD8vIQyKcKa7vJVuIZK/img.png)
'โญ Personal_Study > Vue' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
UX & UI (0) | 2022.11.18 |
---|---|
Todo: Local Storage (0) | 2022.11.16 |
Lifecycle Hooks (0) | 2022.11.14 |
Vuex (0) | 2022.11.14 |
Emit Event (0) | 2022.11.13 |
๋๊ธ