카테고리 없음

[Vue] state-management

황성안 2021. 5. 12. 22:56
728x90
반응형

Vue State-Management

문제

  1. Component가 많아지면 분리하기가 어려워진다( Props, Emit)
  2. 형제 컴포넌트 사이에는 직접적인 교류가 불가능하다 ( 일단 맨위로 올리고 내려야함)

 

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 
TodoListTodoListItem
  
  • 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.todostodos 로 변경이 가능하다.

 

 

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)        }    },

 

 

 

 

교슈님 강조

  1. 컴포넌트에서 dispatch를 활용해 actions를 호출
  2. action에 정의된 메서드는 commit을 활용해 mutations를 호출
  3. 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.함수명
  • mutations, actions => methods

    • mutations 사용법:this.$store.commit('문자열 형태의 함수명', 매개변수)
    • actions 사용법: this.$store.dispatch('mutation 함수명', 매개변수)

 

728x90
반응형