윤시의 블로그

[Vue] Vue.js의 컴포넌트 시스템(props, emit, v-model, slot, provide/inject, teleport) 본문

Vue

[Vue] Vue.js의 컴포넌트 시스템(props, emit, v-model, slot, provide/inject, teleport)

yo09 2025. 2. 21. 08:58

Vue.js의 컴포넌트 시스템은 애플리케이션을 독립적이고 재사용 가능한 단위로 분리하여 관리하는 데 중요한 역할을 한다. 컴포넌트는 부모-자식 관계를 형성하며, 데이터를 효율적으로 전달하고 이벤트를 처리하는 다양한 방법이 있다. 이번 글에서는 Vue 컴포넌트 심화 개념인 props, emit, v-model, slot, provide/inject, teleport에 대해 알아볼 예정이다.

 


1. Props : 부모 → 자식 간 데이터 전달

props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 방법이다. Vue에서는 단방향 데이터 흐름을 유지하며, 부모에서 자식으로 전달된 데이터는 자식에서 수정할 수 없다. 자식은 부모로부터 받은 값을 읽기만 할 수 있고, 수정은 부모 컴포넌트에서만 가능하다.

주요 특징

  • 단방향 데이터 흐름: 부모에서 자식으로만 데이터가 전달된다.
  • 읽기 전용: 자식 컴포넌트에서는 받은 데이터를 수정할 수 없다. 부모에서 값이 변경되면 자식에서 자동으로 반영된다.
  • 유효성 검사: defineProps()를 사용하여 전달되는 데이터의 타입, 필수 여부, 기본값 등을 정의할 수 있다.
<!-- 부모 컴포넌트 -->
<script setup>
import ChildComponent from './ChildComponent.vue';
</script>

<template>
  <ChildComponent title="Vue의 Props" :count="10" />
</template>

<!-- 자식 컴포넌트 -->
<script setup>
const props = defineProps({
  title: String,
  count: Number
});
</script>

<template>
  <h2>{{ title }}</h2>
  <p>Count: {{ count }}</p>
</template>
  • 부모 컴포넌트에서 count 값을 자식에게 전달한다. 자식에서는 count를 읽기만 할 수 있으며, 수정할 수 없다.

📌 props는 단방향 데이터 흐름을 유지해야 한다는 점이 중요하다. 자식에서 값을 변경하려면 emit을 통해 부모에게 변경을 요청해야 한다.

 


 

2. Emit : 자식 → 부모로 이벤트 전파

emit은 자식 컴포넌트에서 발생한 이벤트를 부모 컴포넌트로 전달하는 방법이다. Vue에서는 자식에서 부모로 이벤트를 전파하여 부모가 이를 처리할 수 있게 한다.

주요 특징

  • 이벤트 전달: 자식에서 발생한 이벤트를 부모로 전달한다.
  • 자동 변환: 이벤트 이름은 kebab-case로 작성되며, 자식에서는 camelCase로 호출해도 자동으로 변환된다.
<!-- 부모 컴포넌트 -->
<script setup>
import MyComponent from './MyComponent.vue';

const handleSomeEvent = () => {
  console.log('Event received!');
};
</script>

<template>
  <MyComponent @some-event="handleSomeEvent" />
</template>

<!-- 자식 컴포넌트 -->
<script setup>
const emit = defineEmits(['someEvent']);

const handleClick = () => {
  emit('someEvent');
};
</script>

<template>
  <button @click="handleClick">Click me</button>
</template>
  • 자식 컴포넌트에서 emit('someEvent')를 호출하면 부모 컴포넌트에서 @some-event="handleSomeEvent"가 실행된다.

📌 emit은 부모와 자식 간의 이벤트 통신을 담당하는 핵심 메커니즘이다. 부모는 자식에서 발생한 이벤트를 듣고 적절히 처리할 수 있다.


 

3. v-model : 양방향 데이터 바인딩

v-model은 부모와 자식 컴포넌트 간의 양방향 데이터 바인딩을 가능하게 해준다. Vue 3에서는 defineModel()을 사용하여 v-model을 정의할 수 있다. 부모에서 자식으로 데이터를 전달하고, 자식에서 부모로 변경 사항을 반영할 수 있다.

주요 특징

  • 양방향 바인딩: 부모와 자식 간의 데이터가 자동으로 동기화된다.
  • 여러 개의 v-model: v-model을 여러 번 사용하여 하나 이상의 데이터 바인딩을 할 수 있다.
<!-- 부모 컴포넌트 -->
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const countModel = ref(0);
</script>

<template>
  <ChildComponent v-model="countModel" />
</template>

<!-- 자식 컴포넌트 -->
<script setup>
const model = defineModel();

const increment = () => {
  model.value++;
};
</script>

<template>
  <button @click="increment">Current Value: {{ model }}</button>
</template>
  • 부모는 v-model="countModel"로 데이터를 바인딩하고, 자식 컴포넌트에서 model 값을 수정하면 부모 컴포넌트에서 자동으로 반영된다.

📌 v-model은 양방향 데이터 바인딩을 가능하게 하여 부모와 자식 컴포넌트 간의 데이터 변경을 실시간으로 반영할 수 있다.

 


4. Slot - 부모의 콘텐츠 삽입

slot은 부모 컴포넌트에서 자식 컴포넌트의 특정 위치에 동적으로 콘텐츠를 삽입할 수 있게 해주는 기능이다. 기본 slot과 named slot을 통해 다양한 방식으로 콘텐츠를 전달할 수 있다.

주요 특징

  • 기본 슬롯: 자식 컴포넌트에 삽입된 콘텐츠가 그대로 표시된다.
  • named slot: 특정 이름을 가진 슬롯에 콘텐츠를 전달할 수 있다.
<!-- 부모 컴포넌트 -->
<template>
  <ChildComponent>
    <p>이 부분은 부모에서 전달한 내용입니다.</p>
  </ChildComponent>
</template>

<!-- 자식 컴포넌트 -->
<template>
  <h2>Child Component</h2>
  <slot></slot> <!-- 부모에서 전달한 콘텐츠 삽입 -->
</template>
  • 부모가 ChildComponent에 내용을 넣으면, 자식은 <slot></slot>을 통해 그 내용을 표시한다.

📌 slot은 부모-자식 컴포넌트 간 콘텐츠 삽입을 가능하게 하여 동적인 UI 구성에 유용하다.

 


5. Provide / Inject - 전역 속성 공유

provide와 inject는 부모-자식 관계를 넘어서 컴포넌트 간 데이터 공유를 가능하게 한다. 특히 계층이 깊어지면 prop drilling 문제를 해결하는 데 유용하다.

주요 특징

  • provide: 부모 컴포넌트에서 하위 컴포넌트로 데이터를 제공한다.
  • inject: 자식 컴포넌트에서 부모 컴포넌트가 제공한 데이터를 받아서 사용할 수 있다.
  •  
<!-- 부모 컴포넌트 -->
<script setup>
import { provide } from 'vue';

provide("theme", "dark");
</script>

<template>
  <ChildComponent />
</template>

<!-- 자식 컴포넌트 -->
<script setup>
import { inject } from 'vue';

const theme = inject("theme");
</script>

<template>
  <p>현재 테마: {{ theme }}</p>
</template>
  • 부모는 provide()를 통해 theme를 제공하고, 자식은 inject()로 이를 받아 사용한다.

📌 provide/inject는 중간 컴포넌트가 없이 부모에서 자식으로 데이터를 제공하고 받을 수 있어, prop drilling 문제를 해결한다.


6. Teleport - DOM 위치 이동

teleport는 Vue 3에서 추가된 기능으로, 현재 컴포넌트 구조와 관계없이 원하는 DOM 위치에 요소를 렌더링할 수 있게 해준다. 예를 들어, 모달을 body 태그 내에 렌더링하고 싶을 때 유용하다.

<template>
  <Teleport to="body">
    <div class="modal">모달 창입니다.</div>
  </Teleport>
</template>

<style>
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
}
</style>
  • Teleport는 body 태그에 modal을 렌더링하므로, 컴포넌트의 구조와 관계없이 원하는 위치에 모달을 표시할 수 있다.

📌 teleport는 DOM 구조를 변경하지 않고, 원하는 위치에 요소를 렌더링할 수 있도록 해준다.

'Vue' 카테고리의 다른 글

[Vue] Vue의 반응형 API : 데이터 바인딩  (0) 2025.02.18