Vue

[Vue.js] Vue에서 컴포넌트 간에 데이터 전송하는 방식

에릭 Kim 2024. 6. 28. 12:49
반응형

1. Props와 Emit

setup 

npm install -g @vue/cli // vue cli 설정

vue create my-vue-app // 프로젝트 생성

cd my-vue-app // 디렉토리 이동

 

ChildComponent.vue

<template>
  <div>
    <h2>자식 컴포넌트</h2>
    <p>부모로부터 받은 데이터: {{ data }}</p>
    <button @click="updateData">데이터 업데이트</button>
  </div>
</template>

<script>
import { defineComponent, toRefs } from 'vue';

export default defineComponent({
  name: 'ChildComponent',
  props: {
    data: {
      type: String,
      required: true
    }
  },
  emits: ['updateData'],
  setup(props, { emit }) {
    const { data } = toRefs(props);

    const updateData = () => {
      emit('updateData', '안녕하세요, 부모 컴포넌트!');
    };

    return {
      data,
      updateData
    };
  }
});
</script>

 

ParentComponent.vue

<template>
  <div>
    <h1>부모 컴포넌트</h1>
    <p>부모 데이터: {{ parentData }}</p>
    <ChildComponent :data="parentData" @updateData="handleUpdate" />
  </div>
</template>

<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  setup() {
    const parentData = ref('안녕하세요, 자식 컴포넌트!');

    const handleUpdate = (newData) => {
      parentData.value = newData;
    };

    return {
      parentData,
      handleUpdate
    };
  }
};
</script>

 

2. Mitt 라이브러리 

Mitt 라이브러리란? 

: JavaScript와 TypeScript를 위한 매우 간단하고 작은 이벤트 발행-구독(pub/sub) 라이브러리입니다. MITT는 특히 브라우저 환경이나 Node.js 환경에서 이벤트를 간단하게 관리하기 위해 설계되었습니다. 이 라이브러리는 성능이 뛰어나고, 설치 및 사용이 매우 간편하여 많은 개발자들이 선호합니다.

 

setup

npm install mitt // 라이브러리 설치

 

eventBus.js

import mitt from 'mitt';
const emitter = mitt();
export default emitter;

 

ChildComponent.vue

<template>
  <div>
    <h2>자식 컴포넌트</h2>
    <p>부모로부터 받은 데이터: {{ parentData }}</p>
    <button @click="updateData">데이터 업데이트</button>
  </div>
</template>

<script>
import emitter from '../eventBus';
import { defineComponent, toRefs } from 'vue';

export default defineComponent({
  name: 'ChildComponent',
  props: {
    parentData: {
      type: String,
      required: true
    }
  },
  setup(props) {
    const { parentData: receivedData } = toRefs(props);

    const updateData = () => {
      emitter.emit('updateData', '안녕하세요, 부모 컴포넌트!');
    };

    return {
      receivedData,
      updateData
    };
  }
});
</script>

 

ParentComponent.vue

<template>
  <div>
    <h1>부모 컴포넌트</h1>
    <p>부모 데이터: {{ parentData }}</p>
    <ChildComponent :parentData="parentData" />
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted } from 'vue';
import emitter from '../eventBus';
import ChildComponent from './ChildComponent.vue';

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  setup() {
    const parentData = ref('안녕하세요, 자식 컴포넌트!');

    const handleUpdate = (newData) => {
      parentData.value = newData;
    };

    onMounted(() => {
      emitter.on('updateData', handleUpdate);
    });

    onUnmounted(() => {
      emitter.off('updateData', handleUpdate);
    });

    return {
      parentData,
    };
  }
};
</script>

 

 

3. Vuex와 같은 상태관리 방식 

setup

npm install vuex@next // vueX 설치

 

store 설정

import { createStore } from 'vuex';

export default createStore({
  state: {
    message: '안녕하세요, 자식 컴포넌트!'
  },
  mutations: { // 상태 변경. 동기적 방식
    setMessage(state, newMessage) {
      state.message = newMessage;
    }
  },
  actions: { // 비동기 작업을 포함한 복잡한 로직을 처리
    updateMessage({ commit }, newMessage) {
      commit('setMessage', newMessage);
    }
  },
  getters: { // 상태를 계산하거나 필터링한 결과
    message: (state) => state.message
  }
});

 

main.js

import { createApp } from 'vue';
import App from './App.vue';
import store from './store';

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

 

ChildComponent.vue

<template>
  <div>
    <h2>자식 컴포넌트</h2>
    <p>부모로부터 받은 데이터: {{ message }}</p>
    <button @click="updateData">데이터 업데이트</button>
  </div>
</template>

<script>
import { computed } from 'vue';
import { useStore } from 'vuex';

export default {
  name: 'ChildComponent',
  setup() {
    const store = useStore();
    const message = computed(() => store.getters.message);

    const updateData = () => {
      store.dispatch('updateMessage', '안녕하세요, 부모 컴포넌트!');
    };

    return {
      message,
      updateData
    };
  }
};
</script>

 

ParentComponent.vue

<template>
  <div>
    <h1>부모 컴포넌트</h1>
    <p>부모 데이터: {{ message }}</p>
    <ChildComponent />
  </div>
</template>

<script>
import { computed } from 'vue';
import { useStore } from 'vuex';
import ChildComponent from './ChildComponent.vue';

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  setup() {
    const store = useStore();
    const message = computed(() => store.getters.message);

    return {
      message
    };
  }
};
</script>

 

결과

 

=>

 

Summary

 

  • props 및 emit 방식: 단방향 데이터 흐름이 명확하고, 작은 애플리케이션에 적합함. 그러나 깊이 있는 컴포넌트 구조에서는 복잡해질 수 있음.
  • mitt 라이브러리 방식: 컴포넌트 계층에 구애받지 않고 이벤트를 통해 데이터를 전달 가능. 그러나 네임스페이스 충돌과 이벤트 추적의 어려움이 있을 수 있음.
  • Vuex와 같은 상태 관리 방식: 중앙 집중식으로 상태를 관리하여 대규모 애플리케이션에 적합. 그러나 설정과 사용이 복잡하고, 학습 곡선이 있을 수 있음. 

=> 자신의 프로젝트에 맞는 방식을 채택하면 됨 !! 

 

반응형