본문 바로가기
  • 일하면서 배운 내용 끄적이는 블로그
Vue

Props vs EventBus vs Vuex

by dhl7799 2024. 5. 2.

Props

Vue.js에서는 부모 - 자식 컴포넌트 사이에 단방향 바인딩을 생성한다.

Vue는 컴포넌트로 화면을 구성하기 때문에 같은 웹페이지라도 데이터를 공유할수 없다

 

따라서 부모는 Props를 통해 자식에게 데이터를 전달하고, 자식은 events(emit)을 통해 부모에게 전달한다.

 

예제코드

 

부모

<!-- 부모 컴포넌트 -->
<template>
  <div>
    <!-- ChildComponent에 message라는 prop을 전달, 이때 :message는 v-bind:message의 축약문법 -->
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from ParentComponent!'
    };
  }
};
</script>

 

자식

<!-- 자식 -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    // message props를 정의
    message: String
  }
};
</script>

 

이런 방식으로 데이터를 전달하는것은 규모가 크고 복잡해질수록 컴포넌트 간 통신 및 데이터 전달이 힘들다

 

그래서 다음 방법이 EventBus와 Vuex이다.

EventBus

EventBus는 쉽게 말하면 비어있는 Vue 인스턴스 객체이다.

import Vue from "vue";
var EventBus = new Vue();

 

이 인스턴스를 독립적인 각 컴포넌트 끼리 통신할때 중간다리로 활용하여 부모-자식 관계가 아니어도 통신할수 있게 한다.

(부모자식 관계로 써놓은건 그냥 데이터 전달 방향을 보기쉽게 하기 위함) 

<!-- 부모 -->
<template>
  <div>
    <child-component />
  </div>
</template>

<script>
import EventBus from './EventBus';

export default {
  mounted() {
    // 컴포넌트가 마운트되면 EventBus를 사용하여 데이터를 전달
    EventBus.$emit('message', 'Hello from ParentComponent!');
  }
};
</script>

 

<!-- 자식 -->
<template>
  <div>
    <p>{{ receivedMessage }}</p>
  </div>
</template>

<script>
import EventBus from './EventBus';

export default {
  data() {
    return {
      receivedMessage: ''
    };
  },
  mounted() {
    // EventBus를 사용하여 'message' 이벤트를 구독하고 데이터를 수신
    EventBus.$on('message', message => {
      this.receivedMessage = message;
    });
  }
};
</script>

 

해당 방식으로도 데이터를 주고받을 수 있지만 프로젝트 규모가 커지면 컴포넌트간 데이터 흐름을 파악하기 어려움

(어디서 어디로 보냈는지 관리가 안됨)

 

따라서 이를 해결하기 위한 방식이 Vuex

 

Vuex

Vuex란 Vue.js에서의 상태 관리 라이브러리

Vue.js 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할

React의 Redux같은것

 

특징

 

Single Source of Truth

하나의 어플리케이션은 하나의 store만 가진다

하나의 객체가 어플리케이션 전체 state를 포함

단일 상태 트리는 특정 state를 바로 찾을 수 있게 만들고, 현재 앱의 state의 스냅샷을 가져올 수 있어 디버깅 편리

 

State is Reactive

상태가 변경되면 이 상태를 공유하는 다른 곳에서도 상태가 업데이트 됨 

 

State management pattern + Library

Vuex는 상태관리 패턴이자 라이브러리

여러 컴포넌트 간의 데이터 전달과 이벤트 통신을 한곳에서 관리하는 패턴을 Vuex를 통해 구현

상태관리 및 특정 규칙 적용과 관련된 개념을 정의하고 분리해서 코드의 구조와 유지관리 기능 향상

 

주의사항

페이지 새로고침시 store의 데이터 사라짐

-> 쿠키 or 스토리지나 다른 라이브러리 등으로 처리

vuex-persistedstate 라이브러리

모든 store 값들을 localstorage로 저장하면 속도 이슈 발생

공통적으로 사용하는 상태가 아니라면 메모리 낭비

 

Vuex 저장소가 일반 전역 개체와 다른 두가지

1. 반응형

저장소의 상태가 변경되면 업데이트

2. 상태를 직접 변경할 수 없음

commit을 이용해야함(따라서 모든 상태 추적 가능한 기록 남음)

 

예제

 

store.js

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

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    message: 'Hello from Vuex!'
  },
  mutations: {
    setMessage(state, payload) {
      state.message = payload;
    }
  },
  actions: {
    setMessage(context, payload) {
      context.commit('setMessage', payload);
    }
  }
});

 

state

Vue의 data와 같다.

원본 소스의 역할이며 View와 직접적으로 연결되어있는 Model

state는 mutation을 통해서만 변경이 가능하다

mutation을 통해서 state가 변경되면 반응적으로 View가 업데이트 된다.

 

mutations

state를 변경하는 유일한 방법

일반적으로 commit을 통해서만 호출할 수 있음(Helper 함수로 직접 호출 가능)

첫번째 인자는 state 두번째는 payload

 

주로 api를 통해 전달받은 데이터를 mutations에서 가공하여 state를 설정하는데 사용됨

 

actions

비동기 작업이 가능

(그 외에는 mutations와 비슷)

mutations를 호출하기 위한 commit이 가능

action에서 mutations를 호출하여 state를 변경할 수 있음

dispatch를 통해 호출할 수 있음

첫번째 인자는 context, 두번째 인자는 payload

context는 state, commit, dispatch, rootstate 속성들을 포함

주로 axios를 통한 api 호출과 그 결과에 대해 return을 하거나 mutations로 commit하는 용도로 사용

 

getters

예제에는 없지만 Vue의 computed와 같음(계산된 속성)

getter의 결과는 종속성에 따라 캐시되고 변경된 경우에만 다시 계산

state에 대해 연산을 하고 그 결과를 view에 바인딩 할 수 있음

state의 변경 여부에 따라 다시 게산하고 view를 업데이트

 

modules

모듈별(기능 또는 페이지)로 store를 분리하고 관리 가능

실무에서는 단 하나의 store를 사용하기 힘듬

 

설치는 npm install vuex

 

Vue.use(Vuex)로 명시적으로 추가

 

부모

<!-- 부모 -->
<template>
  <div>
    <child-component />
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  mounted() {
    // Vuex action을 호출하여 데이터를 변경합니다.
    this.setMessage('Hello from ParentComponent!');
  },
  methods: {
    ...mapActions(['setMessage'])
  }
};
</script>

 

자식

<!-- 자식 -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  computed: {
    // Vuex state를 계산된 속성으로 매핑합니다.
    ...mapState(['message'])
  }
};
</script>

 

'Vue' 카테고리의 다른 글

Vue 프로젝트 경로의 @  (0) 2024.05.07
emit으로 자식 -> 부모 데이터 전달  (0) 2024.05.03
Vue 프로젝트 동작 순서  (0) 2024.05.02
Vue 객체의 기본 속성 정리  (0) 2024.05.02
<fragment> 태그  (0) 2024.03.29