부모 컴포넌트로부터 필요한 데이터를 자식 컴포넌트에 props 로 받아올 수 있다.
(상위 컴포넌트 -> 하위 컴포넌트)
//ChildComp.vue
<template>
<div>
{{ msg || "I am childComponent" }}
</div>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
msg: String,
});
</script>
const props = definedProps({
msg: String
})
컴파일 타임 매크로인 definedProps()
내에서 선언한 props 는 template 내부에서 사용할 수 있다. (msg
)
//App.vue
<template>
//속성에 대한 값을 전송하지 않았을 경우
<ChildComponent />
//속성에 대한 값을 전송했을 경우
<ChildComponent :msg="parentMessage" />
</template>
<script setup>
import ChildComponent from "./components/ChildComponent.vue";
const parentMessage = "Hello from parent!";
</script>
속성을 사용하는 것처럼 v-bind 문법을 사용하여 동적으로 바인딩할 수 있다.
과정을 요약하자면
1. 부모 컴포넌트에서 해당 속성에 대해 전송
2. 자식 컴포넌트에서 속성을 받고 등록
3. 자식 컴포넌트에서 사용
부모 컴포넌트는 자식에게 props를 사용하여 데이터를 전달하는 것 외에도, 슬롯을 사용하여 템플릿 조각을 전달할 수 있다.
//ChildComp.vue
<template>
//대체 콘텐츠를 지정하지 않은 경우
<slot></slot>
//대체 콘텐츠가 지정한 경우
<slot>바나나 보이 🍌</slot>
</template>
slot
태그 내부 outlet 에서 부모에게 전달받은 슬롯 컨텐츠를 전달할 수 있다.
전달하지 않은 경우, outlet 에 대체 콘텐츠로 표시될 수도 있다.
//App.vue
<template>
//자식 컴포넌트 태그 사이에 데이터 입력했을 경우
<ChildComponent>테스트</ChildComponent>
//자식 컴포넌트 태그 사이에 입력하지 않았을 경우
<ChildComponent></ChildComponent>
</template>
대체 콘텐츠를 지정하지 않은 경우는 부모 컴포넌트에서 자식 컴포넌트 태그 사이에 테스트라는 HTML 콘텐츠를 지정하였기 때문에 자식 컴포넌트의 slot 태그 위치에 테스트
가 출력된다.
대체 콘텐츠를 지정하고 부모 컴포넌트에서 자식 컴포넌트 태그 사이에 데이터를 입력하지 않다면, 자식 컴포넌트의 slot 태그에서 대체 콘텐츠로 지정한 바나나 보이
가 출력된다.
slot 문법을 사용하여 과정을 간략히 한다면,
1. 자식컴포넌트는 데이터가 나타나야하는 곳에 slot 태그를 위치시킴
2. 부모컴포넌트는 <자식컴포넌트>데이터</자식컴포넌트> 형식을 보냄
3. props 문법 사용없이 부모 컴포넌트에서 설정한 데이터가 자식 컴포넌트에서 보여짐
비슷한 것 같지만 props 문법보다 쉽게 사용할 수 있지만, 단 HTML 태그 처럼 사용할 수 있다.
<template>
<ChildComponent>
<h2>제목</h2>
<span class="free">나는 자유야</span>
</ChildComponent>
</template>
<style>
.free{
background: yello
}
</style>
<template>
<slot></slot>
</template>
이렇게 자식 컴포넌트 slot 의 자리에 부모 컴포넌트에서 단순히 문자열만이 아닌 태그 사이에 입력되는 모든 내용의 콘텐츠들을 출력할 수 있다.
하지만, slot이 간단하게 데이터를 넘겨줄 수 있다는 장점이 있지만, 앞서 살펴본 예제들은 데이터 하나만을 전달했다. 규모가 커지면 부모-자식 컴포넌트 간에 오가는 데이터들이 많아지는 경우가 있다.
//App.vue
<template>
<ChildComponent>
<template v-slot:name1>테스트1</template>
<template v-slot:name2>테스트2</template>
</ChildComponent>
</template>
<template>
<div>
<slot name="name1"></slot>
<slot name="name2"></slot>
</div>
</template>
<template v-slot:{이름}>{데이터}</template>
로 작성한다. 이때, {이름}
은 겹치지 않게 주의한다. <slot name="{이름}"></slot>
으로 작성해주면 같은 {이름}
에 맞게 데이터가 넘어가게 된다.데이터가 많아지면 하나하나 문법에 맞게 다 작성해야하기 때문에 유연성이 부족하고 복잡성이 증가할 수 있다. 그 외에도 프로퍼티 전달과 기본값 처리의 어려움이 있어 slot 문법을 사용하지 않는 것이 좋을 수도 있다.
자식 컴포넌트에서 생성한 이벤트를 부모 컴포넌트에서 해당 이벤트에 대한 리스너를 등록하고 발생시킬 때 사용하는 옵션이다. 부모 컴포넌트는 자식 컴포넌트의 상태를 변경하거나, 특정 행동을 수행하도록 유도할 수도 있다.
//ChildComp.vue
const emit = defineEmits(['response']);
emit('response', '자식 컴포넌트로부터 🌷를 받았어요!')
emit 할 이벤트를 defineEmits
를 이용하여 선언하고, emit 의 첫번째 인자로는 선언한 이벤트로 추가되는 인자는 이벤트 리스너에 전달한다.
//App.vue
const childMsg = ref('자식 컴포넌트로부터 아직 메시지를 받지 못했어요!')
//v-on 사용
<ChildComp v-on:response="(msg) => childMsg = msg" />
//바인딩 사용
<ChildComp @response="(msg) => childMsg = msg" />
부모 컴포넌트에서 해당 이벤트를 수신하고, 메세지 인자를 로컬 상태에 할당시킨다.
Vue 공식 문서의 튜토리얼 을 진행하면서 어려웠던 개념인 props, emits, slots 에 대해 정리해보았다. 튜토리얼은 정말 간략하게 15개 정도의 예제를 볼 수 있었는데 간편한 점은 정말 명확하게 보이는 것 같다. 특히 컴포지션 api의 사용을 해보면서 어느정도의 문법을 익힐 수 있었다.
Stepping into the world of online TV streaming was like entering a portal to a realm of endless entertainment possibilities. On the streaming site I frequented, I found myself transported to worlds both familiar and fantastical, each show and movie offering a unique escape from reality. With each visit, I eagerly explored the platform's vast catalog, immersing myself in stories that spanned every genre and era. Whether I was unraveling https://guia-programacion-tv.es/ mysteries in a gripping crime thriller or laughing along with the antics of a quirky sitcom, there was always something new and exciting to discover. And as I delved deeper into the platform's offerings, I found myself drawn into the rich tapestry of storytelling, connecting with characters and narratives in ways I never thought possible. In the end, it wasn't just about watching TV—it was about experiencing the magic of storytelling, forging connections with characters, and sharing the journey with friends and fellow enthusiasts.