컴포넌트를 사용하면 UI를 독립적이고 재사용 가능한 조각으로 분할하고 각 조각을 독립적으로 생각할 수 있다. 일반적으로 앱은 중첩된 컴포넌트의 트리로 구성된다.
사용자 정의 콤포넌트를 작성할떄 가장 고민되는 것이 부모 콤포넌트와 자식 콤포넌트 사이에 정보 교환인데 보통 아래 규칙을 따른다.
❶ 부모 > 컴포넌트 : Props 를 통하여 전달한다.
❷ 컴포넌트 > 부모 : 이벤트를 발생 시켜 데이터를 전달한다.
❸ 전역 : 전체 프로그램에서 공유가 필요한 데이터의 경우는 pinia Store 를 사용한다.
- /views/Photos.vue : 이미지 목록.
- /components/PhotoCard.vue : 목록에 보여지는 사용자 정의 컴포넌트.
- /store/photos.store.ts : 이미지 데이터를 위한 Store.
❶ Props
v-bind 를 사용해서 부모의 값을 props 에 바인딩 할 수 있다. 부모의 값이 변경되면 동적으로 하위(자식 컴포넌트) 값도 변경된다.
<PhotoCard v-bind:image="image" @imageEditEvent="edit" @imageViewEvent="view"></PhotoCard>
v-bind 를 단축하여 아래와 같이 사용할 수 도 있다.
<PhotoCard :image="image" @imageEditEvent="edit" @imageViewEvent="view"></PhotoCard>
props 는 단반향 바인딩 만을 지원하는데, 이는 자식 컴포넌트가 실수로 부모 콤포넌트의 값을 변경하는 것을 막기 위함이다. props 값을 변경해야 할 필요가 있는 경우 ⑴ 자식 콤포넌트는 초기 값으로 만 사용하고 로컬 값을 생성하여 사용하거나 ⑵ prop 값으로 부터 계산되는 값을 사용하는 것이다.
⑴ prop 값으로 로컬 값을 초기화하여 사용
const props = defineProps({
image: Object,
})
const localImage = ref(props.image)
⑵ prop 값으로 부터 계산되는 값을 사용
const props = defineProps({ attachment: Object })
const emit = defineEmits(['previewEvent'])
const thumbnailUrl = computed(() => {
return attachments.isAudio(props.attachment) ? attachments.thumbnails.AUDIO :
attachments.getAttachmentUrl(props.attachment,
{ thumbnail: true, width: 300, height: 300 });
})
❷ 커스텀 이벤트
커스텀 이벤트를 사용하면 자식 컴포넌트에서 부모에게 값을 전달 할 수 있다.
자식 컴포넌트
<template>
<v-btn size="small" color="white" variant="text" icon="mdi-eye"
@click="emit('imageViewEvent', image)"></v-btn>
</template>
<script setup lang="ts">
defineProps({
image: Object,
})
const emit = defineEmits(['imageEditEvent', 'imageViewEvent'])
</script>
부모 컴포넌트
<PhotoCard :image="image" @imageEditEvent="edit" @imageViewEvent="view"></PhotoCard>
⓷ Pinia Store
Vuex 와 다르게 Pinia 를 라이브러리를 사용하면 아주 쉽게 저장소를 생성하고 전역으로 공유할 수 있다.
이미지 목록을 가져오는 Photos.vue 컴포넌트에서 fetch 함수를 사용하여 데이터를 가져온다. Store 의 상태는 전역으로 공유가 되기 때문에 다른 뷰로 이동하고 다시 돌아오는 경우에도 Store 가 가지고 있는 정보는 유지되어 사용할 수 있다.
onMounted 함수 내에서 store에서 정보를 가져오는 코드를 포함하여 구현하는 경우 불필요한 서버 통신을 최소화할 수 있어 편리하게 사용할 수 있다.
import { usePhotosStore } from '@/store/photos.store'
const photos = usePhotosStore()
const images = ref([])
onMounted(async () => {
if (!photos.isLoaded) {
overlay.value = true
photos.setPage(1)
await photos.fetch()
overlay.value = false
}
images.value = photos.photos
})
댓글 없음:
댓글 쓰기