WEB/Vue.js
[Vue.js] Vuex
Raymond
2022. 8. 13. 20:52
Vuex
Vuex는 Vue.js 애플리케이션을 위한 상태 관리 패턴 + 라이브러리 입니다. 모든 컴포넌트를 위한 중앙 집중식 저장소를 제공해 줍니다. 그렇기 때문에 중앙 저장소에 저장된 데이터는 쉽게 바꿀 수 있는게 아니고, 특정 함수(mutations, actions)를 통해서만 데이터 변경이 가능하게하고 변경 상태를 관리할 수 있습니다.
Vuex 사용법
state, getter, mutations, actions, modules로 상태를 관리합니다.
state : vue에서의 data영역과 같은 역할을 합니다.
getter : vue에서의 computed영역과 같은 역할을 합니다.
mutations : state의 데이터를 바꿀수 있는 유일한 역할을 합니다.
actions : mutations 하고 비슷한데, mutations에 정의한 함수를 커밋(commit)시켜서 state를 변경 + 비동기 처리가 가능
modules : 용도에 맞게 js파일을 나누어서 모듈화하여 사용을 하는 경우 사용이 된다.
기본구조
import { createStore } from 'vuex'
export default createStore({
state() {
return {
todos: [
{ id: 1, title: 'todo 1', done: true },
]
}
},
getters: {
doneTodosCount(state) {
return state.todos.filter((todo) => todo.done).length
}
},
mutations: {
doneYN(state, doneStatus) {
state.todos.filter((todo) => todo.id === doneStatus.id)[0].done =
doneStatus.done
}
},
actions: {
add({ commit }, item) {
// const {commit, state} = context
// context.commit, context.state
// 서버랑 통신. fetch, axios
commit('add', item)
}
// add2: async ({ commit }, item) => {
// await fetch('', {})
// }
},
modules: {}
})
todo 예제
폴더구조
project
|--src
|--store
| |--index.js
| |--todo.js
|--views
| |--vuex
| |--TodoView.vue
|--main.js
index.js
import { createStore } from 'vuex'
import { todo } from './todo'
// 새로고침 해도 영구적으로 데이터가 남아있게 만드는 모듈
import persistedstate from 'vuex-persistedstate'
export default createStore({
modules: {
todo: todo
},
plugins: [persistedstate({ paths: ['todo.todos'] })]
})
persistedstate 모듈
데이터를 도메인 Local Storage에 저장을 해주는 모듈
사용처 : 장바구니, 마직막 접속페이지
vue cookies 모듈
유저의 데이터와 같이 영구적이지 않지만 일정시간이후에 데이터를 날려야 하는 경우 사용되는 모듈
사용처 : 유저 데이터(로그인시)
todo.js
export const todo = {
// namespaced를 true로 해줘야 index.js에서 moduls에 todo를 넣을수 있다.
namespaced: true,
state() {
return {
todos: [
{ id: 1, title: 'todo 1', done: true },
{ id: 2, title: 'todo 2', done: false },
{ id: 3, title: 'todo 3', done: false }
]
}
},
getters: {
todosCount(state) {
return state.todos.length
},
doneTodosCount(state) {
return state.todos.filter((todo) => todo.done).length
},
notDoneTodosCount(state) {
return state.todos.filter((todo) => !todo.done).length
}
},
mutations: {
add(state, item) {
state.todos.push(item)
},
remove(state, id) {
state.todos = state.todos.filter((todo) => todo.id !== id)
},
doneYN(state, doneStatus) {
state.todos.filter((todo) => todo.id === doneStatus.id)[0].done =
doneStatus.done
}
},
actions: {
add({ commit }, item) {
commit('add', item)
}
}
}
TodoView.vue
<template>
<div>
<div>{{ todos }}</div>
<div>할일 목록 전체수 : {{ todosCount }}</div>
<div>완료 목록 수 : {{ doneTodosCount }}</div>
<div>미완료 목록 수 : {{ notDoneTodosCount }}</div>
<div>
<label for="todo" class="form-label">할일</label>
<input
type="text"
name=""
id="todo"
class="form-control"
v-model="todo"
/>
<button class="btn btn-primary" @click="addItem">추가(mutation)</button>
<button class="btn btn-primary" @click="addItem2">추가(action)</button>
</div>
<div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Todo ID</th>
<th>할일</th>
<th>완료여부</th>
<th></th>
</tr>
</thead>
<tbody>
<tr :key="todo.id" v-for="todo in todos">
<td>{{ todo.id }}</td>
<td>{{ todo.title }}</td>
<td>
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="flexSwitchCheckChecked"
:checked="!todo.done"
@change="doneYN(todo.id, $event)"
/>
</div>
</td>
<td>
<button
class="btn btn-danger btn-sm"
@click="removeItem(todo.id)"
>
삭제
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
todo: ''
}
},
computed: {
todos() {
return this.$store.state.todo.todos
},
todosCount() {
return this.$store.getters['todo/todosCount']
},
doneTodosCount() {
return this.$store.getters['todo/doneTodosCount']
},
notDoneTodosCount() {
return this.$store.getters['todo/notDoneTodosCount']
}
},
setup() {},
created() {},
mounted() {},
unmounted() {},
methods: {
addItem() {
this.$store.commit('todo/add', { id: 4, title: this.todo, done: false })
},
removeItem(id) {
this.$store.commit('todo/remove', id)
},
doneYN(id, event) {
this.$store.commit('todo/doneYN', { id: id, done: !event.target.checked })
},
addItem2() {
// dispatch로 actions에 접근가능
this.$store.dispatch('todo/add', { id: 4, title: this.todo, done: false })
}
}
}
</script>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
const app = createApp(App)
app.use(store)
app.use(router)
app.mount('#app')