[Vue.js] Non-Prop 속성 (fallthrough 속성)

토끼는 개발개발·2023년 10월 18일
0

Vue.js

목록 보기
15/19
post-thumbnail

📌 Non-Prop 속성(fallthrough 속성)

Non-Prop 속성은 props 또는 event 에 명시적으로 선언되지 않은 속성 또는 이벤트이다. (ex. class, style, id)

이전포스팅(emits)에서 '왜 이벤트를 선언해야 하는가?'라는 질문에 'vue가 non-prop 속성에 알려진 리스너(Fallthrough)를 제외할 수 있기 때문'이라고 답한적이 있다.

이번 포스팅은 저 문장을 이해하는 포스팅이 될 것이다.
결론은 간단해서 포스팅을 망설였으나, 'why'에 집중하기에 포스팅을 작성해본다.

먼저, 당연하듯 예시부터 살펴보겠다.
LabelInput.vue라는 자식 컴포넌트가 있고, 이를 부모 컴포넌트에서 다음과 같이 사용했다고 가정해보자.

<!--부모 컴포넌트-->
<LabelInput label="이름" class="non-class" style="color: red">

자식 컴포넌트의 이벤트 선언 부분을 살펴보자.

export default{
	props:['label']
}

label은 props에 선언되어 있지만, classstyle은 props에 선언되어 있지 않다. 이때 선언되어 있지 않은 classstyle같은 속성 또는 이벤트를 Non-prop 속성이라 한다.

그럼 이 속성들은 어떻게 될까?
루트 요소의 속성에 자동으로 추가된다. 속성 상속이 이루어지는 것이다.



1. 속성 상속

Non-prop 속성은 루트요소에 자동으로 추가된다.

class, style 속성 병합

만약, 자식 컴포넌트 루트요소에 이미 classstyle 속성이 정의되어 있으면, 부모로부터 받은 classstyle 속성과 병합한다.

이 외는 덮어씌운다.

v-on 이벤트 리스너 상속

<labelInput @click="onClick">

@click 리스너는 <labelInput> 컴포넌트 루트요소에 추가된다.
만약 루트요소에 이미 바인딩된 이벤트가 있다면 두 리스너 모두 트리거 된다.

여기서 주의해야할 점은, 루트요소에 추가된다는 것이다.
루트요소에 이벤트가 추가되면 의도치 않은 상황이 발생할 수 있다.

예를 들어, 자식 컴포넌트 labelInput.vue가 다음과 같이 작성되어 있다고 가정해보자.

<template>
  <div class="bg-danger">
    <button type="button">버튼</button>
  </div>
</template>

부모컴포넌트에서 상속받은 non-props 이벤트리스너 @click="onClick"은 루트요소인 <div class="bg-danger">에 상속될 것이다.

즉, 나는 버튼을 클릭했을 때만 이벤트를 실행시키고 싶은데 <div>영역을 클릭하면 이벤트가 실행되는 현상이 나타나는 것이다.

어떻게 해결해야할까? 이때 필요한것이 속성 상속의 비활성화이다.



2. 속성 상속 비활성화

컴포넌트가 자동으로 Non-Prop 속성을 상속하지 않도록 하기위해 컴포넌트의 inheritAttrs: false 옵션을 설정할 수 있다.

<script>
export default {
  inheritAttrs: false,
};
</script>

컴포넌트에 Non-Prop 속성을 비활성화 하는 일반적인 경우는 자식 컴포넌트의 루트요소에 이외의 다른 요소에 Non-Prop 속성을 적용하고 싶을 때이다.

그리고 적용해야하는 요소에 <template>에서 Non-Prop속성에 접근할 수 있는 내장 객체 $attrs로 직접 접근할 수 있다.

$attrs 객체에는 컴포넌트에 선언되지 않은 모든 속성 props, emits (ex. class, style, v-on 등)을 포함하고 있다.

<template>
  <div>
    <button v-bind="$attrs">버튼</button>
  </div>
</template>

스크립트 셋업에서는 context로 접근할 수 있다.

<script>
export default(){
	inheritAttrs: false,
    setup(props, context){
    	console.log(context.attrs);
    	console.log(context.attrs.class);
        console.log(context.attrs.onClick);
    }
}
</script>

💡 주의사항

  • props와 달리 Non-Prop 속성은 JavaScript에서 원래 대소문자를 유지하므로 foo-bar와 같은 속성은 대괄호를 사용하여 $attrs[’foo-bar’]로 접근해야 한다.

  • @click과 같은 v-on리스너는 $attrs.onClick과 같이 함수로 접근할 수 있다.




3. 여러 루트노드의 속성 상속

Vue3에서는 다중 루트 노드 컴포넌트인 fragments를 공식 지원한다.

vue2에서는 다중 루트 노드가 지원되지 않아서 단일 <div>로 감싸야했다.

<template>
  <div>
  	<header>...</header>
    <main>...</main>
  </div>
</template>

하지만, vue3부터는 다중 루트 노드를 가질 수 있다.
다만, 속성을 배포(상속)해야 하는 위치를 명시적으로 정의해야한다. (non-props 속성을 어느 루트에 상속해야 하는지 알지 못하기 때문)

<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>

단일 루트 요소가 있는 컴포넌트와 달리 여러 루트 요소가 있는 컴포넌트에는 자동으로 Non-Prop 속성이 상속되지 않는다.
만약 명시적으로 $attrs를 바인딩 하지 않을 경우 런타입 경고가 발생된다.




참고문헌

vue3 공식문서 fallthrough
vue3 완벽마스터 - 짐코딩

profile
하이 이것은 나의 깨지고 부서지는 샏 스토리입니다

0개의 댓글