v-on, v-bind를 이용해 바인딩을 간소화하는 방법을 알아봅니다.
이전 시리즈
2022.12.21 - [Vue.js] - Vue3 컴포넌트 디자인 패턴 소개
2022.12.22 - [Vue.js] - Vue3 컴포넌트 디자인 패턴 : Props
2022.12.22 - [Vue.js] - Vue3 컴포넌트 디자인 패턴 : Slots
2022.12.22 - [Vue.js] - Vue3 컴포넌트 디자인 패턴 : Scoped Slots
모든 것을 지배하는 하나의 객체
<input
:id="inputId"
:data-tooltip="tooltipText"
@change="updateForm"
@mouseover="showTooltip"
/>
인수 없이 v-bind
<template>
<img v-bind:src="imageAttrs.source" v-bind:alt="imageAttrs.text" />
</template>
<script>
export default {
data() {
return {
imageAttrs: {
src: '/vue-mastery-logo.png',
text: 'Vue Mastery Logo'
}
}
}
}
</script>
이 구문은 사실 v-bind 객체에 인수를 전달함으로써 특정 속성을 이 특정 속성에 바인딩하고 싶다고 Vue에 알리는 것입니다.
그러나 더 당혹스러운 것은 이 인수가 옵셔널하다는 것입니다.
믿거나 말거나 우리 코드는 실제로 다음과 같이 작성할 수 있습니다.
<img v-bind="{ src: imageAttrs.source, alt: imageAttrs.text }" />
<img v-bind="imageAttrs" />
인수 없이 v-on
<template>
<img v-on:click="openGallery" v-on:mouseover="showTooltip" />
</template>
<script>
export default {
methods: {
openGallery() { ... },
showTooltip() { ... }
}
}
</script>
v-bind와 마찬가지로 우리가 정의한 이벤트 이름은 실제로 v-on 객체에 전달되는 인수입니다.
결과적으로 img 요소를 다음과 같이 다시 작성할 수도 있습니다.
<template>
<img v-on="{ click: openGallery, mouseover: showTooltip }" />
</template>
<template>
<img v-on="inputEvents" />
</template>
<script>
export default {
computed: {
inputEvents: {
click: this.openGallery,
mouseover: this.showTooltip
}
},
methods: {
openGallery() { ... },
showTooltip() { ... }
}
}
</script>
그러나 앞서 v-bind 섹션에서 언급한 것처럼 우리 대부분은 이해하기 쉽고 필요한 경우 변경하기 쉽기 때문에
여전히 원래 구문을 선호합니다.
언제 이것이 유용한가요?
NewsFeed Scenario
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
:article-title="content.title"
:article-content="content.body"
:ad-image="content.image"
:ad-heading="content.heading"
@click="content.type === 'NewsArticle' ? openArticle : openAd"
@mouseover="content.type === 'NewsArticle' ? showPreview : trackAdEvent"
/>
</main>
</template>
- Component 컴포넌트를 사용, content.type에 의해 결정되는 is 속성을 사용해 NewsArticle 또는 NewsAd 컴포넌트를 동적으로 렌더링합니다.
- NewsArticle 컴포넌트 바인딩 동적 속성: atricle-title, article-content
- NewsAd 컴포넌트 바인딩 동적 속성: ad-image, ad-heading
특정 prop과 이벤트는 특정 컴포넌트에만 중요하다는 것이 분명합니다.
속성 및 이벤트 목록이 길어지면 컴포넌트이해 및 관리가 점점 어려워 질 것이 분명합니다.
Refactoring NewsFeed
컴포넌트 이해 및 관리가 어려워지면 새로운 기술과 추상화를 찾아야 할 때입니다.
배운 기술을 사용하여 NewsFeed 컴포넌트를 리팩터링해 보겠습니다.
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
v-bind="feedItem(content).attrs"
v-on="feedItem(content).events"
/>
</main>
</template>
<script>
export default {
methods: {
feedItem(item) {
if (item.type === 'NewsArticle') {
return {
attrs: {
'article-title': item.title,
'article-content': item.content
},
events: {
click: this.openArticle,
mouseover: this.showPreview
}
}
} else if (item.type === 'NewsAd') {
return {
attrs: {
'ad-image': item.image,
'ad-heading': item.heading
},
events: {
click: this.openAd,
mouseover: this.trackAdEvent
}
}
}
}
}
}
</script>
이를 통해 단일 HTML 엘리먼트에 여러 컴포넌트의 관심사를 섞지 않으면서,
특정 컴포넌트에 대한 책임을 적절하게 위임했습니다.
마치며
코드 리팩터링의 주요 지표는 가독성과 관리용이성 입니다.
객체 구문으로 추상화 하기 전에 이렇게 하면 코드 읽기가 쉬울지, 관리하기 쉬울지(관심사의 분리)를 생각해보세요
'FrontEnd' 카테고리의 다른 글
Vue3 컴포넌트 디자인 패턴 : expose (0) | 2022.12.25 |
---|---|
Vue3 컴포넌트 디자인 패턴 : v-model (0) | 2022.12.22 |
Vue3 컴포넌트 디자인 패턴 : Scoped Slots (0) | 2022.12.22 |
Vue3 컴포넌트 디자인 패턴 : Slots (0) | 2022.12.22 |
Vue3 컴포넌트 디자인 패턴 : Props (0) | 2022.12.22 |