[Vue] state-management
Vue State-Management
문제
- Component가 많아지면 분리하기가 어려워진다( Props, Emit)
- 형제 컴포넌트 사이에는 직접적인 교류가 불가능하다 ( 일단 맨위로 올리고 내려야함)
Vuex 4가지 구성요소
state
getters
mutations state를 변경할때 동기적으로 생각할떄
- actions에서 state로 갈수가없다. 그래서 mutations을 거쳐서 data 변경을 가능
- 동기적인 친구(data 변경 추적)
actions : 비동기적으로 변경할떄
VueX 설치하기
vue add vuex
- 기본적인 설정을 vue가 다 해준다.
세팅하기
vue create 0512
cd 0512
#
App 안에 TodoForm과 TodoList를 만들고
TodoList안에 TodoListItem을 만든다
App | |
---|---|
TodoForm | |
TodoList | TodoListItem |
components 안에 TodoListItem.vue 만들기
components 안에 TodoList.vue 만들기
compoent 를 등록하는 3단계
불러오기
import TodoListItem from '@/components/TodoListItem'
등록하기(export default 안에 name 밑에)
components: { TodoListItem, }
사용하기(div 안에)
<TodoListItem/>
components 안에 TodoList.vue 만들기
App.vue 에 TodoForm, TodoList 불러오기
compoent를 등록하는 3단계
불러오기
import TodoForm from '@/components/TodoForm' import TodoList from '@/components/TodoList'
등록하기
components: { TodoForm, TodoList, }
사용하기
<div id="app"> <TodoForm/> <TodoList/> </div>
시작해보자
결국 State === data 이다.
todo의 데이터들을 state에다가 작성을해보겠습니다.
store > index.js 안에 state 에 todos 를 추가해준다.
state: { todos: [ { title: '할 일1', completed: false, }, { title: '할 일2', completed: false, } ] },
TodoList.vue
- store에 접근을해서 공유를 한다.
div 안의 TodoListItem 에 아래 코드 추가
store 안에 state 안의 todos, 그리고 idx
<TodoListItem v-for="(todo, idx) in $store.state.todos" :key="idx"/>
computed 추가
computed: { todos: function () { return this.$store.state.todos } }
- 여기까지오면 위의 div에서
in $store.state.todos
는todos
로 변경이 가능하다.
TodoListItem.vue
props 해준다.
<script>export default { name: 'TodoListItem', props: { todo: { type: Object, } }}</script>
- 할 일을 띄워준다.
<template> <div> {{ todo.title }} </div></template>
TodoForm.vue
todoform 을 이용해서 입력시켜 할일을 띄워보자
template( 엔터칠떄 되게하는거 @keyup.enter="createTodo"
)
<template> <div> <input type="text" @keyup.enter="createTodo"> <button>Add</button> </div></template>
script
<script>export default { name: 'TodoForm', data: function() { return { todoTitle: '', } }}</script>
엔터치게끔하는거 활성화
확인해보는 코드 개발자도구에서 찍히는지 확인.
methods: { createTodo: function() { console.log('Todo 생성!') } }
index.js
상태를 변경시키게 하는건 mutations 다.
mutations 가 state.todos에 추가를 해줘야한다
mutations 호출은 action 이 commit을 통해 호출된다.
mutations 는 항상 state (상태)를 받는다
mutations: { CREATE_TODO: function(state) { console.log(state) } },
왜 어퍼(_)케이스를 사용할까?
- 이녀석들은 데이터를 조작하는 함수들이
_
를 사용한다.
TodoForm.vue
methods 에서 mutations를 연결시켜준다.
methods: { createTodo: function() { this.$store.commit('CREATE_TODO') } }
todo가 작성될수있는 로직을 만들어보자
methods: { createTodo: function() { const todoItem = { title: this.todoTitle, completed: false, } this.$store.commit('CREATE_TODO', todoItem) } }
index.js
mutations
mutations: { CREATE_TODO: function(state, todoItem) { //console.log(state) state.todos.push(todoItem) } },
TodoForm.vue
Actions - Component 에서 Dispath() 메서드에 의해 호출
항상 context가 인자로 넘어온다 , 단 state를 직접 변경하지는 않는다
mutations에 정의된 메서드를 commit 메서드로 호출한ㄴ다
state는 오로지 mutations 메서드를 통해서만 조작한다
<template> <div> <input type="text" v-model="todoTitle" @keyup.enter="createTodo"> <button @click="createTodo">Add</button> </div></template><script>export default { name: 'TodoForm', data: function() { return { todoTitle: '', } }, methods: { createTodo: function() { const todoItem = { title: this.todoTitle, completed: false, } this.$store.commit('CREATE_TODO', todoItem) this.todoTitle = '' } }}</script><style></style>
index.js 의 actions 작성
엑션에서 콘솔로 호출하여 확인하기위해선 Todoform에서 methods 에 dispatch를 호출해야한다.
actions: { createTodo: function(context) { console.log(context) } },
교슈님 강조
- 컴포넌트에서 dispatch를 활용해 actions를 호출
- action에 정의된 메서드는 commit을 활용해 mutations를 호출
- mutations에 정의된 메서드는 state를 조작한다.
actions를 이용해서 선택한부분만 출력해보기
createTodo: function({commit, state}, todoItem) { //console.log(context) commit('CREATE_TODO', todoItem) }
-
-
실습 수업
셋팅하고
Vuex 다운받고
Components 만들고
Profile.vue
<template> <div> <h1>Profile Page</h1> <p>이름 : 황성안</p> <p>특징 : 3대 460 ㅠㅠ</p> </div></template><script> export default { name: 'Profile',}</script><style></style>
app.vue
<template> <div id="app"> <Profile/> <button>Login</button> </div></template><script>import Profile from '@/components/Profile'export default { name: 'App', components: { Profile, }, data() { return { isAuthenticated: false, } },}</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 id="app"> <Profile v-if="isAuthenticated" /> <button @click="login">Login</button> </div></template><script>import Profile from '@/components/Profile'export default { name: 'App', components: { Profile, }, data() { return { isAuthenticated: false, } }, methods: { login() { this.isAuthenticated = true }, },}</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>
- 머하는거라고?
app.vue
<template> <div id="app"> <Profile /> <button @click="login">Login</button> </div></template><script>import Profile from '@/components/Profile'export default { name: 'App', components: { Profile, }, data() { return {} }, methods: { login() { }, },}</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'Vue.use(Vuex)export default new Vuex.Store({ state: { //사용할 데이터를 저장하는 곳 token: null, }, getters: { //computed처럼 사용 isAuthenticated(state) { const result = state.token ? true :false return result }, }, mutations: { // state를 변경하는 함수를 정의하는 곳 }, actions: { // state를 "비동기적으로" 변경할 때 사용하는 // 함수를 정의하는 곳 // 주의) 반드시 mutations를 통해 "간접적으로" 변경할 것 }, modules: { }})
app.vue
this.$store
는 index.js의 store까지를 나타낸다.- getters 중앙에 올려두고 app의 computed 에서 getters를 가져온다.
<template> <div id="app"> <Profile v-if="isAuthenticated"/> <button @click="login">Login</button> </div></template><script>import Profile from '@/components/Profile'export default { name: 'App', components: { Profile, }, data() { return {} }, methods: { login() { this.$store.state.token ='1234qwer!@#$%^&' }, }, computed: { isAuthenticated() { return this.$store.getters.isAuthenticated }, },}</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>
이방법 절때 쓰지마세요
- state에 값을 그대로넣어주니까 노노
methods: { login() { this.$store.state.token ='1234qwer!@#$%^&' }, },
새로운 방법
index.js
간접적인 방법으로 바꿔줘야한다 mutations에 stat.token을 넣어주는것
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({ state: { //사용할 데이터를 저장하는 곳 token: null, }, getters: { //computed처럼 사용 isAuthenticated(state) { const result = state.token ? true :false return result }, }, mutations: { // state를 변경하는 함수를 정의하는 곳 UPDATE_TOKEN(state, newToken) { state.token = newToken }, }, actions: { // state를 "비동기적으로" 변경할 때 사용하는 // 함수를 정의하는 곳 // 주의) 반드시 mutations를 통해 "간접적으로" 변경할 것 }, modules: { }})
app.vue
<template> <div id="app"> <Profile v-if="isAuthenticated"/> <button @click="login">Login</button> </div></template><script>import Profile from '@/components/Profile'export default { name: 'App', components: { Profile, }, data() { return {} }, methods: { login() { const token = '!#H!%VK!#4h1j23hk1h24k!' this.$store.commit('UPDATE_TOKEN', token)// git의 commit => 기록을 하는 행위 }, }, computed: { isAuthenticated() { return this.$store.getters.isAuthenticated }, },}</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
- commit 이 mutations 로 이동하고 playload 가 newToken 으로이동한다
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({ state: { //사용할 데이터를 저장하는 곳 token: null, }, getters: { //computed처럼 사용 isAuthenticated(state) { const result = state.token ? true :false return result }, }, mutations: { // state를 변경하는 함수를 정의하는 곳 UPDATE_TOKEN(state, newToken) { state.token = newToken }, }, actions: { // state를 "비동기적으로" 변경할 때 사용하는 // 함수를 정의하는 곳 // 주의) 반드시 mutations를 통해 "간접적으로" 변경할 것 GET_TOKEN_FROM_SERVER({commit}, payload) { // ontext (객체): state, commit, getters.... commit('UPDATE_TOKEN', payload) }, },})
app.vue
<template>
<div id="app">
<Profile v-if="isAuthenticated"/>
<button @click="login">Login</button>
</div>
</template>
<script>
import Profile from '@/components/Profile'
export default {
name: 'App',
components: {
Profile,
},
data() {
return {}
},
methods: {
login() {
const token = '!#H!%VK!#4h1j23hk1h24k!'
//this.$store.commit('UPDATE_TOKEN', token)// git의 commit => 기록을 하는 행위
this.$store.dispatch('GET_TOKEN_FROM_SERVER', token)
},
},
computed: {
isAuthenticated() {
return this.$store.getters.isAuthenticated
},
},
}
</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>
만약에 장고서버로 요청을 보내야한다면
axios.get(''/login')
app.vue(최종)
<template>
<div id="app">
<Profile v-if="isAuthenticated"/>
<button @click="login">Login</button>
</div>
</template>
<script>
import Profile from '@/components/Profile'
export default {
name: 'App',
components: {
Profile,
},
data() {
return {}
},
methods: {
login() {
const token = '!#H!%VK!#4h1j23hk1h24k!'
//this.$store.commit('UPDATE_TOKEN', token)// git의 commit => 기록을 하는 행위
//this.$store.dispatch('GET_TOKEN_FROM_SERVER', token)
},
},
computed: {
isAuthenticated() {
return this.$store.getters.isAuthenticated
},
},
}
</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>
배운거
Vuex Cheatsheet
Vuex 기본 요소
- state
- getters
- mutations
- actions
활용법
state, getters => computed
- state 사용법 :
this.$store.state
- getters 사용법:
this.$store.getters.함수명
- state 사용법 :
mutations, actions => methods
- mutations 사용법:
this.$store.commit('문자열 형태의 함수명', 매개변수)
- actions 사용법:
this.$store.dispatch('mutation 함수명', 매개변수)
- mutations 사용법: