[Vue.js] Vuex 시작(1) - State

dl_edge·2021년 9월 28일
1

Vue.js

목록 보기
2/5
post-custom-banner

💎 Vuex 시작 (1)

Vue.js의 컴포넌트와 컴포넌트간 통신 방법을 알고 있다는 전제하에 시작한다.


Vuex란?

  • Vue.js의 상태 관리를 위한 패턴이자 라이브러리.

  • 다른 상태 관리 패턴이나 라이브러리와 비교했을 때 뷰의 반응성 체계를 효율적으로 활용하여 화면을 업데이트 한다는 차이점이 있다.


Vue의 상태관리는 왜 필요할까?

  • 컴포넌트 기반 프레임워크에서는 작은 단위로 쪼개진 여러 개의 컴포넌트로 화면을 구성한다.
  • 이에 따라 컴포넌트 간의 통신이나 데이터 전달을 좀 더 유기적으로 관리할 필요성이 생긴다.

상태 관리란?

상태 관리란, 여러 컴포넌트 간의 데이터 전달과 이벤트 통신을 한 곳에서 관리하는 패턴을 의미한다.


상태 관리로 해결할 수 있는 문제점?

상태 관리는 중대형 규모의 웹 애플리케이션에서 컴포넌트 간에 데이터를 더 효율적으로 전달할 수 있다.

일반적으로 앱의 규모가 커지면서 생기는 문제점들은 아래와 같다.

  1. 뷰의 컴포넌트 통신 방식인 props, event emit 때문에 중간에 거쳐야할 컴포넌트가 많아지거나
  2. 이를 피하기 위해 Event Bus를 사용하여 컴포넌트 간 데이터 흐름을 파악하기 어려운 것

이러한 문제점을 해결하기 위해 모든 데이터 통신을 한 곳에서 중앙 집중식으로 관리하는 것이 상태 관리다.


상태 관리 패턴

[상태 관리 구성요소]

  • state: 컴포넌트 간에 공유할 data
  • view: 데이터가 표현될 template
  • actions: 사용자의 입력에 따라 반응할 methods

new Vue({
  // state = > 공유할 데이터
  data() {
    return {
      counter: 0
    };
  },
  // view
  template: `
    <div>{{ counter }}</div>
  `,
  // actions
  methods: {
    increment() {
      this.counter++;
    }
  }
});

위 구성요소는 아래와 같은 단방향 흐름으로 동작한다.


🎨 예제 #1 - 간단한 Vue App

뷰엑스를 알아보기 위해 버튼으로 숫자를 늘리고 줄일 수 있는 카운터 앱을 만들어보자. Vue CLI로 프로젝트를 생성한 다음 아래와 같이 Parent, Child 컴포넌트를 제작한다.


App.vue (Parent component)

<!-- App.vue(parent) -->
<template>
  <div id="app">
    Parent counter : {{ counter }} <br>
    <button @click="addCounter">+</button>
    <button @click="subCounter">-</button>

    <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props로 전달한다. -->
    <child v-bind:num="counter"></child>
  </div>
</template>

<script>
// chilc 컴포넌트 import
import Child from "./Child.vue";

export default {
  components: {
    // child 컴포넌트를 App.vue의 하위 컴포넌트로 등록
    child : Child
  },

// data 등록
  data(){
    return {
      counter: 0
    };
  },
  methods: {
    // 이벤트 추가
    addCounter(){
      this.counter++;
    },
    subCounter(){
      this.counter--;
    }
  }
};
</script>

Child.vue (Child Component)

<template>
    <div>
        <hr>
        Child counter : {{ num }} <br>
        <button>+</button>
        <button>-</button>
    </div>  

</template>

<script>
export default {
    // 상위 컴포넌트에서 내려준 counter 속성을 num으로 받음
    props: ["num"]
};
</script>

하위 컴포넌트인 Child.vue는 App.vue에게서 props 속성으로 counter를 받는다.

그래서, 결국은 App.vue의 +를 누르거나 -를 눌러도 child.vue의 counter도 같은 값을 가지게 된다.


다르게 말해, 같은 데이터 속성을 2개의 컴포넌트에서 접근하여 같은 값을 표현하고 있다는 것이다. 이 구조는 뷰의 props 속성을 이용한 기본적인 컴포넌트 통신 방법이다.

  • 만약 한 화면에서 표시해야 할 컴포넌트의 갯수가 무한정 많아진다면?
  • 최상위 컴포넌트에서 최하위 컴포넌트에 데이터를 전달하기 위해 중간 계층의 컴포넌트에 모두 props, event emit을 선언해야 한다.

이 비효율적인 컴포넌트 간 데이터 전달 방식을 Vuex로 해결할 수 있다!:mask:


🎨 Vuex 예제 #2 - Vuex 설치 및 등록

  1. Vuex 설치
npm install vuex

  1. 뷰엑스를 등록할 .js 파일 새로 생성. 이름은 관례에 따라 store.js로 지정
// store.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export const store = new Vuex.Store({
  // ...
});
  1. 프로젝트의 main.js 파일로 가서 store.js를 불러와 등록한다.
import Vue from "vue";
import App from "./App.vue";
import router from "./router";

// store.js를 불러오는 코드
import { store } from "./store.js";

Vue.config.productionTip = false;

new Vue({

  // 뷰 인스턴스의 store 속성에 연결
  store: store,
  router,
  render: h => h(App)

}).$mount("#app");

🎨 Vuex 예제 #3 - state 등록

state를 vuex에 추가한다.

// store.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export const store = new Vuex.Store({
  // counter 라는 state 속성을 추가
  state: {
    counter: 0
  }
});

state에 정의된 counter속성은 Parent 컴포넌트에서 사용하던 data 속성 counter와 동일한 역할을 합니다. 이미 앞 상태 관리 패턴에서 설명했듯이, state는 컴포넌트 간에 공유할 data 속성을 의미한다.


🎨 Vuex 예제 #4 - state 접근

vuex의 state에 등록한 counter 속성은 컴포넌트 템플릿 코드에서 $store.state.counter접근할 수 있다.

<!-- App.vue(parent) -->
!<template>
  <div id="app">
    Parent counter : {{ $store.state.counter }} <br>
    <button @click="addCounter">+</button>
    <button @click="subCounter">-</button>

  <!-- 기존코드 -->
    <!-- Child 컴포넌트를 등록하고 counter 데이터 속성을 props로 전달한다. -->
   <!-- <child v-bind:num="counter"></child> -->
   <child></child> 
  </div>
</template>

<script>
// chilc 컴포넌트 import
import Child from "./Child.vue";

export default {
  components: {
    // child 컴포넌트를 App.vue의 하위 컴포넌트로 등록
    child : Child
  },

/* 기존코드
// data 등록
  data(){
    return {
      counter: 0
    };
  }, */
  methods: {
    addCounter(){
      //this.counter++;
      this.$store.state.counter++;
    },
    subCounter(){
      //this.counter--;
      this.$store.state.counter--;
    }
  }
};
</script>

위 코드는 기존 App.vue 코드와 2가지가 다르다.

  1. data 속성으로 선언한 counter 값 제거
  2. Child 컴포넌트로 counter를 전달하지 않음 (props 사용 x)

결국 Parent 컴포넌트에서 관리하던 counter 데이터를 Vuex의 state에 넘겨줬다.

Child 컴포넌트에서 접근하던 Parent 컴포넌트의 data 속성이 Vuex로 갔기 때문에 이제 Child에서는 Vuex의 state를 바라보면 된다.

이제 Parent와 Child 모두 state에 접근할 수 있게 된 것. 이외에 모든 컴포넌트는 state에 접근을 할 수 있다.



Vuex를 사용하고 나서도, Parent 컴포넌트의 + 버튼을 눌렀을 때 동일하게 동작하는 것을 볼 수 있다.

동일하게 Child 컴포넌트에도 뷰엑스 적용해보자.

!<template>
    <div>
        <hr>
        Child counter : {{ $store.state.counter }} <br>
        <button>+</button>
        <button>-</button>
    </div>  
</template>

<script>
export default {
    // 상위 컴포넌트에서 내려준 counter 속성을 num으로 받음
    /* 기존 코드
    props: ["num"]
    */
};
</script>

Parent 컴포넌트에서 props 속성으로 counter를 전달받던 방식에서 Vuex의 state인 counter를 바로 접근하는 방식으로 변경했다.




📕 REFERENCE: [캡틴판교] https://joshua1988.github.io/web-development/vuejs/vuex-start/

profile
TIL (Today I Learned!) 전공 까먹기 싫어서 정리하는 중🎁
post-custom-banner

0개의 댓글