Vue 11-2 Vuex Project ๊ตฌํ˜„

Seungju Hwangยท2021๋…„ 1์›” 23์ผ
0

Vue

๋ชฉ๋ก ๋ณด๊ธฐ
16/18
post-thumbnail

Intro

๐Ÿ”ต ใ„ฑใ„ฑ

  • ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์— ์ผ€ํ”ผํƒˆ์ด ๋“ค์–ด๊ฐ€๋ฉด ์•ˆ๋œ๋‹ค๋Š” ๊ฑฐ ์ด์ œ ์•Œ์•˜์–ด์š”...
$vue create todolist
$npm i --save vuex 
$vue add vuex

TodoForm

1. ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

<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 ์–‘ ๋์˜ ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

2. store/index.js ์ˆ˜์ •

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์—์„œ๋Š” ์ด์ œ ๋ฐ์ดํ„ฐ์˜ ์ƒํƒœ๋ฅผ ๋ณ€ํ™”์‹œํ‚ต๋‹ˆ๋‹ค.

3. App.vue

<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 : ์‚ฌ์šฉํ•˜๊ธฐ

TodoList

1. ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

<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๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

2. App.vue

<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>

์ปดํฌ๋„ŒํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ, ๋“ฑ๋กํ•˜๊ธฐ, ์‚ฌ์šฉํ•˜๊ธฐ

Todo

1. ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

<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์œผ๋กœ ์ƒํƒœ ์ •๋ณด๋ฅผ ๋ณด๋ƒ„

2. store/index.js ์ˆ˜์ •

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์—์„œ ์‹ค์ œ๋กœ ๋ณ€๊ฒฝ์‹œํ‚ค๊ธฐ!

3. components/TodoList ๋“ฑ๋ก ๋ฐ ์ˆ˜์ •

<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 ํ—ฌํผ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ !!

getters ์‚ฌ์šฉํ•˜๊ธฐ

1. store/index.js

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

2. App.vue์—์„œ ํ™œ์šฉํ•˜๊ธฐ

<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์— ์žˆ๋Š” ์ƒํƒœ ํ™œ์šฉํ•˜๊ธฐ

๊ฒฐ๊ณผ



profile
๊ธฐ๋กํ•˜๋Š” ์Šต๊ด€์€ ์‰ฝ๊ฒŒ ๋ฌด๋„ˆ์ง€์ง€ ์•Š์•„์š”.

0๊ฐœ์˜ ๋Œ“๊ธ€