동일한 사진 데이터가 한 화면에 다양한 위치에서 여러 번 출력될 수 있다.
하지만 해당 페이지를 구성하는 컴포넌트가 여러 개라면 각 컴포넌트가 개별적으로 동일한 데이터를 관리해야 할까?
그렇다면 사진을 변경해야 할 때 모든 컴포넌트에 대해 변경 요청을 해야한다.
=> "공통된 부모 컴포넌트에서 관리하자"
부모는 자식에게 데이터를 전달(pass props)하며, 자식은 자신에게 일어난 일을 부모에게 알림(emit events)
Props
- 부모 컴포넌트로부터 자식 컴포넌트로 데이터를 전달하는데 사용되는 속성
- 모든 props는 자식 속성과 부모 속성 사이에 하향식 단방향 바인딩(one-way-down binding) 형성
- 부모 속성이 업데이트되면 자식으로 흐르지만 그 반대는 안됨
- 자식 컴포넌트 내부에서 props를 변경하려고 시도해서는 안 되며 불가능
- 부모 컴포넌트가 업데이트될 때마다 자식 컴포넌트의 모든 props가 최신 값으로 업데이트됨
- 단방향인 이유: 하위 컴포넌트가 실수로 상위 컴포넌트의 상태를 변경하여 데이터 흐름을 이해하기 어렵게 만드는 것 방지
예시를 위해 먼저 App > Parent > ParentChild 컴포넌트 관계를 작성한다.
<!-- App.vue -->
<script setup>
import Parent from '@/components/Parent.vue'
</script>
<template>
<div>
<Parent/>
</div>
</template>
<!-- Parent.vue -->
<script setup>
import ParentChild from '@/components/ParentChild.vue'
</script>
<template>
<div>
<ParentChild/>
</div>
</template>
<!-- ParentChild.vue -->
<script setup>
</script>
<template>
<div>
</div>
</template>
Props 작성
부모 컴포넌트 Parent에서 자식 컴포넌트 ParentChild에 보낼 props를 작성한다.
<!-- Parent.vue -->
<script setup>
import ParentChild from '@/components/ParentChild.vue'
</script>
<template>
<div>
<ParentChild my-msg="message"/>
</div>
</template>
이 때 prop 이름은 my-msg, prop 값은 messsage이다.
Props 선언
부모 컴포넌트에서 보낸 props를 사용하기 위해서는 자식 컴포넌트에서 명시적인 props 선언이 필요하다.
Props 선언에는 2가지 방식이 있다.
1. 문자열 배열을 사용한 선언
- defineProps()를 사용하여 props를 선언
<!-- ParentChild.vue -->
<script setup>
defineProps(['myMsg'])
</script>
2. 객체를 사용한 선언 (★ 사용권장)
- 각 객체 속성의 키는 props의 이름이 되며, 객체 속성의 값은 값이 될 데이터의 타입에 해당하는 생성자 함수(Number, String, ...)여야 함
<!-- ParentChild.vue -->
<script setup>
defineProps({
myMsg: String
})
</script>
Prop 데이터 사용
- 템플릿에서 반응형 변수와 같은 방식으로 활용한다.
<!-- ParentChild.vue -->
<template>
<div>
<p>{{ myMsg }}</p>
</div>
</template>
- props를 객체로 반환하므로 필요한 경우 Javascript에서 접근 가능하다.
<!-- ParentChild.vue -->
<script setup>
const props = defineProps({
myMsg: String
})
console.log(props)
</script>
Props 세부사항
1. Props Name Casing (Props 이름 컨벤션)
- 선언 및 템플릿 참조 시: camelCase
<p>{{ myMsg }}</p>
defineProps({
myMsg: String,
})
- 자식 컴포넌트로 전달 시: kebab-case (HTML 속성 표기법과 동일)
<ParentChild my-msg="message"/>
2. Static Props & Dynamic Props
- 지금까지 작성한 것은 정적 props이다!
- v-bind를 사용하여 동적으로 할당된 props를 사용할 수 있다.
1) Dynamic props 정의
<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
const name = ref('Alice')
</script>
<template>
<div>
<ParentChild my-msg="message" :dynamic-props="name"/>
</div>
</template>
2) Dynamic props 선언 및 출력
<!-- ParentChild.vue -->
<script setup>
defineProps({
myMsg: String,
dynamicProps: String
})
</script>
<template>
<div>
<p>{{ dynamicProps }}</p>
</div>
</template>
Emit
$emit() : 자식 컴포넌트가 이벤트를 발생시켜 부모 컴포넌트로 데이터를 전달하는 역할의 메서드
'$' 표기는 Vue 인스턴스나 컴포넌트 내에서 제공되는 전역 속성이나 메서드를 식별하기 위한 접두어!
emit 메서드 구조
$emit(event, ...args)
- event: 커스텀 이벤트 이름
- args: 추가 인자
이벤트 발신 및 수신
- ParentChild에서 $emit을 사용하여 someEvent라는 이름의 사용자 정의 이벤트를 발신
<!-- ParentChild.vue -->
<template>
<div>
<button @click="$emit('someEvent')">클릭</button>
</div>
</template>
- Parent는 v-on을 사용하여 발신된 이벤트 수신
<!-- Parent.vue -->
<script setup>
import ParentChild from '@/components/ParentChild.vue'
const someCallback = function () {
console.log('ParentChild가 발생한 이벤트를 수신했어요.')
}
</script>
<template>
<div>
<ParentChild @some-event="someCallback"/>
</div>
</template>
emit 이벤트 선언
- defineEmits()를 사용하여 명시적으로 발신할 이벤트를 선언할 수 있다.
- script에서 $emit 메서드에 접근할 수 없기 때문에 defineEmits()는 $emit 대신 사용할 수 있는 동등한 함수를 반환한다.
<!-- ParentChild.vue -->
<script setup>
const emit = defineEmits(['someEvent'])
const buttonClick = function () {
emit('someEvent')
}
</script>
<template>
<div>
<button @click="buttonClick">클릭</button>
</div>
</template>
이벤트 인자
- 이벤트 발신 시 추가 인자를 전달하여 값을 제공할 수 있다.
<!-- ParentChild.vue -->
<script setup>
const emit = defineEmits(['emitArgs'])
const emitArgs = function () {
emit('emitArgs', 1, 2, 3)
}
</script>
<template>
<div>
<button @click="emitArgs">추가 인자 전달</button>
</div>
</template>
<!-- Parent.vue -->
<script setup>
import ParentChild from '@/components/ParentChild.vue'
const getNumbers = function (...args) {
console.log(args)
console.log(`ParentChild가 전달한 추가인자 ${args}를 수신했어요.`)
}
</script>
<template>
<div>
<ParentChild @emit-args="getNumbers"/>
</div>
</template>
Event 세부사항
Event Name Casing
- 선언 및 발신 시: camelCase
<button @click="$emit('someEvent')">클릭</button>
const emit = defineEmits(['someEvent'])
emit('someEvent')
- 부모 컴포넌트에서 수신 시: kebab-case
<ParentChild @some-event="..."/>
'Frontend > Vue3' 카테고리의 다른 글
[Vue3] 상태 관리 라이브러리 Pinia (0) | 2024.05.14 |
---|---|
[Vue3] Vue Router로 페이지 이동하기 (0) | 2024.05.08 |
[Vue3] Lifecycle Hooks (0) | 2024.05.06 |
[Vue3] watch (0) | 2024.05.06 |
[Vue3] 리스트 렌더링 (v-for) (0) | 2024.05.06 |