Vue Components - Props가 아닌 속성

YEZI🎐·2022년 11월 29일
0

Vue

목록 보기
19/45

props가 아닌 속성

props가 아닌 속성은 컴포넌트로 전달되지만 props로는 정의되지 않은 속성이다.

임의의 속성

명시적으로 정의된 props는 하위 컴포넌트에 정보를 전달하는데 쓰이지만,
컴포넌트 라이브러리 작성자는 컴포넌트가 사용될 수 있는 상황을 항상 예측할 수 없기 때문에,
컴포넌트는 임의의 속성을 추가할 수 있다.

예를 들어, childComp 컴포넌트에 add-something-attr라는 임의의 속성을 추가할 수 있는 것이다.

<childComp add-something-attr="true"></childComp>

그러면 add-something-attr="true" 속성는 자동으로 childComp 컴포넌트에 추가된다.

존재하는 속성 교체∙병합

다음 소스가 childComp이라는 템플릿이라고 가정했을 때

<div class="child-original"></div>

childComp 컴포넌트에게 다음과 같은 특정 클래스를 추가한다면

<childComp
  class="parent-add"
></childComp>

이 경우, 2개의 다른 값이 class 정의되는 것이다.

  • child-original : 템플릿 내에서 설정한 class
  • parent-add : 부모에 의해 컴포넌트에 전달되는 class

대부분의 속성의 경우 컴포넌트에 제공된 값이 컴포넌트에 의해 설정된 값을 대체한다.
예를 들어, type="date" 속성에 type="text"가 전달되면 속성 값이 대체돼 버려 망가지게 되는 것이다.
다행히 class와 style은 예외로 두 값이 합쳐지기 때문에
최종 class는 class="child-original parent-add"이 된다.

v-on을 이용한 사용자 정의 이벤트

$emit을 이용한 자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달

모든 Vue 인스턴스는 다음과 같은 이벤트 인터페이스를 구현한다.

  • $on(eventName) : 이벤트 감지
    부모 컴포넌트는 자식 컴포넌트가 사용되는 템플릿에서 v-on을 사용하여 자식 컴포넌트에서 보내진 이벤트를 청취할 수 있다.
  • $emit(eventName) : 이벤트 트리거
// 자식 컴포넌트
Vue.component('childComp', {
  template: '<button v-on:click="childMethod">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    childMethod: function () {
      this.counter += 1
      this.$emit('vOnEventName')
    }
  },
})
<!-- 부모 컴포넌트 -->
<div id="parentComp">
  <p>{{ total }}</p>
  <childComp v-on:vOnEventName="parentMethod"></childComp>
  <childComp v-on:vOnEventName="parentMethod"></childComp>
</div>
// 부모 컴포넌트
new Vue({
  el: '#parentComp',
  data: {
    total: 0
  },
  methods: {
    parentMethod: function () {
      this.total += 1
    }
  }
})

.sync

일부 경우 양방향 바인딩이 필요할 수 있다.
자식 컴포넌트가 .sync를 가지는 속성을 변경하면 값의 변경이 부모에 반영된다.
편리하지만 단방향 데이터 흐름이 아니기 때문에 장기적으로 유지보수에 문제가 생길 수 있다.
자식 속성을 변경하는 코드는 부모의 상태에 영향을 미친다.

// 자식 컴포넌트
this.$emit('update:syncEventName', this.counter);
<!-- 부모 컴포넌트 -->
<comp :syncEventName.sync="bar"></comp>
<!-- ↑ 같은 거 ↓ -->
<comp :syncEventName="bar" @syncEventName:foo="val => bar = val"></comp>

사용자 정의 이벤트를 사용한 폼 입력 컴포넌트

<!-- ❕v-model의 작동원리❕ -->
<input v-model="something">
<!-- ↑ 같은 거 ↓ -->
<input v-bind:value="something" v-on:input="something = $event.target.value">

사용자 정의 이벤트는 v-model에서 작동하는 사용자 정의 입력을 만드는 데에도 사용할 수 있다.

<custom-input :value="something" @input="value => { something = value }"></custom-input>

따라서 v-model을 사용하는 컴포넌트는

  • value prop를 가짐
  • 새로운 값으로 input 이벤트를 내보냄

컴포넌트의 v-model 사용자 정의

기본적으로 컴포넌트의 v-model은 value를 보조 변수로 사용하고 input을 이벤트로 사용하지만
체크 박스와 라디오 버튼과 같은 일부 입력 타입은 다른 목적으로 value 속성을 사용할 수 있다.
model 옵션을 사용하면 다음 경우에 충돌을 피할 수 있다.

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
<base-checkbox v-model="foo"></base-checkbox>
<!-- ↑ 같은 거 ↓ -->
<base-checkbox 
  :checked="foo"
  @change="val => { foo = val }">
</base-checkbox>

비 부모-자식 간 통신

때로는 두 컴포넌트가 서로 통신해야 하지만 서로 부모∙자식이 아닐 경우가 있다.
간단한 시나리오에서는 비어있는 Vue 인스턴스를 중앙 이벤트 bus로 사용할 수 있다.

var bus = new Vue()
// 컴포넌트 A의 메소드
bus.$emit('id-selected', 1)
// 컴포넌트 B의 created 훅
bus.$on('id-selected', function (id) {
  // ...
})


References

profile
까먹지마도토도토잠보🐘

0개의 댓글