만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/frontend

[vue] 스스로 만들어보는 To Do List - 2 : Vuex 적용

D36choi 2021. 11. 6. 16:43
728x90

2021.10.31 - [프로그래밍/frontend] - [vue] 스스로 만들어보는 To Do List - 1

 

[vue] 스스로 만들어보는 To Do List - 1

vue.js 강의를 들었으니 스스로 만들어보자 우리 팀에서 사용하는 프론트엔드 프레임워크는 vue.js 다. 이 프레임워크를 이용해 모바일웹과 앱 뷰어를 통해, 우리 팀이 관리중인 영역에서의 사용자

choichumji.tistory.com

1을 통해 간단히 입력창과 버튼을 통해 리스트를 추가해보았다. 이제 새로운 vue 라이브러리를 써보고, 좀 더 그럴싸하게 바꿔봐야겠다.

vuex 를 추가해 상태관리를 쉽게 해보자

이전에는 props, emit 등을 활용해 컴포넌트간 데이터 전달과 이벤트 전달로 할일 추가를 구현했다.

하지만 만약 앱이 커지면 이런 방식으로는 머리가 아파질 수 있다.

애플리케이션의 크기가 커질수록 데이터가 거쳐야하는 컴포넌트가 많아지고 복잡해져서 로직파악이 어려울 때가 있다고 한다.

우리 팀에서 다루는 vue 앱을 볼때는 그런게 덜했는데 알고보니 그때 사용된 것이 vuex였다.

vuex 가 필요한 이유

vue의 중앙형 상태 관리 및 저장소

vuex가 없다면, 상태 변화 흐름을 파악하는데 힘들 수 있다

만약 이름을 변경하는 컴포넌트가 있다고 하자. 이름을 보여주는 이름표 컴포넌트와는 관계의 거리가 상당히 멀다. '이름' 이라는 상태 변화의 흐름을 파악하려면 시간이 오래걸리고 복잡하며, 연관되어있는 컴포넌트끼리 emit, props 등의 키워드가 추가되는 게 강제될 것이다.

컴포넌트 간의 관계가 복잡하면, 써야하는 코드도 많아져 피곤해진다.

Vuex를 전역적인 중앙 관리소로 사용한다면 간단하고 편리해진다

상태를 관리하기 위해 Vuex라는 저장창고를 둔다면 위 그림처럼 복잡해지는 컴포넌트 트리에서도 상태관리가 편리해질 것이다.

Vuex 로 기존코드를 변경해보자

나의 경우에는 vuex 적용을 통해 이전에 props,emit으로 App.vue에서 다른 컴포넌트들로 관리했던 할일 목록 todos을 vuex로 관리할 것 이다.

1. 설치 (next는 최신 버전의미, vue3사용자인 경우 권장
npm install --save vuex@next

 

2. src/ 위치에 store.js 생성 후 코드 입력

import {createStore} from 'vuex'
// 저장소 생성이라고 보면된다
const store = createStore({
  state() {
    return {
      // 컴포넌트에서 접근가능
      todos: []
    }
  },
  mutations: {
    // state 변수는 외부 컴포넌트에서 수정 불가능하므로
    // mutation 내 정의된 함수를 이용해야 상태의 변경 가능하다
    addTodo(state, content) {
      state.todos.push(content)
    }
  }
})

export default store

vuex는 state, mutations, actions 로 구분된다.
state로는 전역변수로 사용하고 싶은 (즉, 모든 컴포넌트에서 접근가능하게 하고픈) 데이터들을 정의하면 된다.
mutations 에는 setter함수를 정의한다고 보면 된다. 외부 컴포넌트에서는 state 값들을 함부로 변경하지 않고 mutation 로 정의된 메서드들만을 통해서 상태가 변경될 수 있게 해야한다.
프로젝트가 커지면 커질수록 아무데서나 그때 상황에 맞게 상태를 변경한다면 찾기도 힘들고 문제가 생길수도 있으니 지혜로운 규칙이다라고 생각한다.

 

3. main.js 에 Vuex 사용하도록 추가

    // src/main.js
    import {createApp} from 'vue'
    import App from './App.vue'
    import store from './store.js'

    const app = createApp(App)  
    app.use(store)  
    app.mount('#app')

vuex 라이브러리를 사용할 수 있도록 main.js 에 추가한다.

 

4.할일 Input 컴포넌트를 바꿔보자

// src/components/ToDoInput.vue
<template>
  <div id="todoinput">
    <input type="text" v-model="content" @keypress.enter="addToDo" />
    <button type="button" @click="addToDo">제출</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      content: ''
    }
  },
  methods: {
    addToDo() {
      // vuex commit
      this.$store.commit('addTodo', this.content)
      this.content = ''
    }
  }
}
</script>

<style></style>

기존에 props, emit 을 활용해 상위하위 컴포넌트간 데이터/이벤트를 전달하던 방식에서 vuex를 활용하도록 바꾸었다.
addToDo() 메서드에서 this.$store.commit('addTodo', this.content) 를 통해 vuex의 mutation 함수 내에 정의된 addTodo 메서드를 호출하게 된다.
vuex에서는 commit() 이라는 메서드를 통해서 mutation 함수를 컴포넌트에서 호출할 수 있도록 해준다. 첫번째 인자에 실행시키려는 mutation 메서드 이름을 넣고, 2번째 파라미터부터는 전달하려는 payload 값을 던져주면 된다.

 

5. 할일목록 출력 컴포넌트를 바꿔보자

    // src/components/ToDoList.vue
    <template>
    <div id="todolist">
     <div id="container" v-for="data in todos" :key="data.id">
       <li id="text">{{ data }}</li>
     </div>
    </div>
    </template>
    ```


<script>export default { computed: { todos() { return this.$store.state.todos } } }</script>

vuex 상태를 불러오기 위해서는 $store.state 가 필수이다. 그래서 상태값 불러오는 코드는 필연적으로 길어진다
그래서 사용된 컴퓨티드(computed) 속성은 템플릿의 데이터 표현을 더 직관적이고 간결하게 도와주는 속성이다.
만약 불러오려는 값이 길어질때 그대로 template영역에 불러오게 된다면 가독성이 매우 나빠질 것이다.
또한 template의 표현식은 최대한 가독성을 높여야하는 것을 vue에서도 권장한다

  • computed 활용X : <div id="container" v-for="data in this.$store.state.todos" :key="data.id">
  • computed 활용 : <div id="container" v-for="data in todos" :key="data.id">

vuex에서는 getter라는 기능도 지원하는데, 그건 나중에 해보도록 해야겠다.
위처럼 바꾸고 npm run serve를 통해 실행해보았다.

 

적용 전과 같이 잘 동작한다

 

vuex로의 변경을 잘 마무리했다. vue는 라이브러리 하나하나 적용하는 것도 간단하고 이해하기 쉽다는 생각이 든다.

 

공부해가며 만들어가는거라 퀄리티는 허접하지만 이해는 더 잘 되는 것 같다.

 

다음은 그럴싸하게 todo item에 시간이나 달성조건 등을 구현해보자