$vue create todolist
$npm i --save vuex
$vue add vuex
<template>
<div>
<label for="todoinput">ํ ์ผ: </label>
<input
type="text"
id="todoinput"
v-model.trim="todo"
@keypress.enter="createTodo"
>
<button @click="createTodo">Add</button>
</div>
</template>
<script>
export default {
name:'TodoForm',
// #1
data() {
return {
todo:'',
}
},
methods: {
createTodo() {
const todoItem = {
title: this.todo,
completed: false,
}
if(todoItem && todoItem.title.trim())
// #2
this.$store.dispatch('createTodo',todoItem)
this.todo=''
}
}
}
</script>
<style>
</style>
#1 : TodoForm ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ ๋ฐ์ดํฐ ๋ณ์
#2 : dispatch
๋ฅผ ํตํด์ todoItem์ store์ actions
๋ก ๋ณด๋ด๊ธฐ
#3 : .trim
์ ๋์ ๊ณต๋ฐฑ์ ์ ๊ฑฐํฉ๋๋ค.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
// #1
todos:[
{title:'ํ ์ผ1',completed:false},
{title:'ํ ์ผ2',completed:true},
]
},
mutations: {
// #3
CREATE_TODO(state,todoItem) {
state.todos.push(todoItem)
}
},
actions: {
// #2
createTodo({commit},todoItem) {
commit('CREATE_TODO',todoItem)
}
},
modules: {
}
})
#1 : todos๋ผ๋ ์์ดํ
์ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด (๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ state
์ ์๋ค.)
#2 : TodoForm ์ปดํฌ๋ํธ์์ dispatch
๋ฉ์๋๋ฅผ ํตํด ๋ณด๋ธ ๋ฐ์ดํฐ๋ฅผ commit
๋ฉ์๋ฅด๋ฅผ ํ์ฉํ์ฌ store์ mutations
๋ก ๋ณด๋ด๊ธฐ
#3 : mutations
์์๋ ์ด์ ๋ฐ์ดํฐ์ ์ํ๋ฅผ ๋ณํ์ํต๋๋ค.
<template>
<div id="app">
<h1>Todo List</h1>
<h2>์ ์ฒด: </h2>
<h3>์๋ฃ: </h3>
<h3>๋ฏธ์๋ฃ: </h3>
// #3
<TodoForm />
</div>
</template>
<script>
// #1
import TodoForm from '@/components/TodoForm'
export default {
name: 'App',
components: {
// #2
TodoForm,
}
}
</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>
#1 : ๋ถ๋ฌ์ค๊ธฐ
#2 : ๋ฑ๋กํ๊ธฐ
#3 : ์ฌ์ฉํ๊ธฐ
<template>
<div>
<ul
v-for="(todo,idx) in todos"
:key="idx"
>
<li>{{todo.title}}</li>
</ul>
</div>
</template>
<script>
export default {
name:'TodoList',
computed: {
// #1
todos() {
return this.$store.state.todos
}
}
}
</script>
<style>
</style>
#1 : this.$store.state.todos
๋ฅผ ํตํด ์ค์ ์ง์ค ์ ์ฅ์์ ์๋ todos๋ฅผ ๋ถ๋ฌ์จ๋ค.
<template>
<div id="app">
<h1>Todo List</h1>
<h2>์ ์ฒด: </h2>
<h3>์๋ฃ: </h3>
<h3>๋ฏธ์๋ฃ: </h3>
<TodoForm />
<TodoList />
</div>
</template>
<script>
import TodoForm from '@/components/TodoForm'
import TodoList from '@/components/TodoList'
export default {
name: 'App',
components: {
TodoForm,
TodoList,
}
}
</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>
์ปดํฌ๋ํธ ๋ถ๋ฌ์ค๊ธฐ, ๋ฑ๋กํ๊ธฐ, ์ฌ์ฉํ๊ธฐ
<template>
<div>
<span
:class="{completed: todo.completed}"
@click="updateTodoStatus"
>
{{todo.title}}
</span>
<button @click="deleteTodo">X</button>
</div>
</template>
<script>
export default {
name: 'Todo',
// #1
props:{
todo:Object,
},
methods: {
// #2
updateTodoStatus() {
this.$store.dispatch('updateTodoStatus',this.todo)
},
// #3
deleteTodo() {
this.$store.dispatch('deleteTodo',this.todo)
}
}
}
</script>
<style>
.completed{
text-decoration: line-through;
}
</style>
#1 : ์์ ์ปดํฌ๋ํธ์ธ TodoList์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ด
#2, #3 : dispatch
๋ฉ์๋๋ฅผ ํตํด store์ action์ผ๋ก ์ํ ์ ๋ณด๋ฅผ ๋ณด๋
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todos:[
{title:'ํ ์ผ1',completed:false},
{title:'ํ ์ผ2',completed:true},
]
},
mutations: {
CREATE_TODO(state,todoItem) {
state.todos.push(todoItem)
},
// #3
DELETE_TODO(state,todoItem) {
const idx = state.todos.indexOf(todoItem)
state.todos.splice(idx,1)
},
// #4
UPDATE_TODO_STATUS(state,todoItem) {
state.todos = state.todos.map((todo)=> {
if(todo===todoItem) {
return {
...todo,
completed: !todo.completed
}
}
return todo
})
}
},
actions: {
createTodo({commit},todoItem) {
commit('CREATE_TODO',todoItem)
},
// #1
deleteTodo({commit},todoItem) {
commit('DELETE_TODO',todoItem)
},
// #2
updateTodoStatus({commit},todoItem){
commit('UPDATE_TODO_STATUS',todoItem)
}
},
modules: {
}
})
#1, #2 : ์ปดํฌ๋ํธ์์ ๋์ด์จ ๋ณ๊ฒฝ๋ ์ํ์ ๋ณด๋ฅผ commit
๋ฉ์๋๋ฅผ ํตํด mutation
์ผ๋ก ๋ณด๋ด์ค
#3, #4 : ์์
์์ ๋ณด๋ด์ค ๋ณ๊ฒฝ๋ ์ํ์ ๋ณด๋ฅผ mutations์์ ์ค์ ๋ก ๋ณ๊ฒฝ์ํค๊ธฐ!
<template>
<div>
<!-- #1 -->
<Todo
v-for="(todo,idx) in todos"
:key="idx"
:todo="todo"
/>
</div>
</template>
<script>
// #2
import {mapState} from 'vuex'
import Todo from '@/components/Todo'
export default {
name:'TodoList',
components: {
Todo
},
// #2
computed: {
...mapState([
'todos',
])
}
}
</script>
<style>
</style>
#1 : Todo ์ปดํฌ๋ํธ ๋ฑ๋กํด์ ์ฌ์ฉํ๊ธฐ
โญ #2 : map ํฌํผ ๋ฉ์๋ ์ฌ์ฉํ๊ธฐ !!
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from "vuex-persistedstate"
Vue.use(Vuex)
export default new Vuex.Store({
state: { //์ํ -> ์ค์๊ด๋ฆฌ
todos: [
{title:'ํ ์ผ1',completed:false},
{title:'ํ ์ผ2',completed:false}
]
},
// #1
getters:{
allTodosCount: function (state) {
return state.todos.length
},
completedTodosCount: function (state) {
return state.todos.filter((todo) => {
return todo.completed === true
}).length
},
uncompletedTodosCount: function (state) {
return state.todos.filter((todo) => {
return todo.completed === false
}).length
},
},
mutations: { // state๋ฅผ ๋ณ๊ฒฝํ๋ ๋ก์ง / ๋๊ธฐ์ ์ผ๋ก ์์ฑ -commit ๋ฉ์๋ ๋ถ๋ฌ์ค๊ธฐ
//...
},
actions: { // ๋ชจ๋ ๋ก์ง/ ์ธ๋ถ๋ฐ์ดํฐpetching/๊ฐ๊ณต: context -> mutations์ ๋ถ๋ฌ์ state ๋ณ๊ฒฝ - dispatch
//...
},
plugins: [
createPersistedState(),
]
})
#1 : ๊ณ์ฐ๋ ๊ฐ -> state๋ณ๊ฒฝํ์ง ์๋ data
<template>
<div id="app">
<h1>Todo List</h1>
<h2>์ ์ฒด : {{allTodosCount}}</h2>
<h3>์๋ฃ : {{completedTodosCount}}</h3>
<h3>๋ฏธ์๋ฃ : {{uncompletedTodosCount}}</h3>
<TodoForm />
<TodoList />
</div>
</template>
<script>
// #1
import {mapGetters} from 'vuex'
import TodoForm from '@/components/TodoForm'
import TodoList from '@/components/TodoList'
export default {
name: 'App',
components: {
TodoForm,
TodoList,
},
// #1
computed: {
...mapGetters([
'allTodosCount',
'completedTodosCount',
'uncompletedTodosCount',
])
}
}
</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>
โญ #1 : map ํฌํผ๋ฉ์๋ ์ฌ์ฉํด์ ์ฝ๊ฒ store์ ์๋ ์ํ ํ์ฉํ๊ธฐ