티스토리 뷰

Vue.JS

[Vue.JS] 컴포넌트 (고급:props)

버미노트 2019. 1. 21. 01:23

1. prop 표기법 (camelCase VS kebab-case)

HTML 속성은 대소문자를 구별하지 않습니다. 모든 대문자를 소문자로 인식합니다. Vue에서 HTML을 표현 할 때 보통 kebal-case로 표현하고, JavaScript에서 prop를 받아 사용할 때는 camelCase를 사용합니다.

<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>

HTML에서는 kebal-case(post-title)를 사용합니다.

Vue.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

JavaScript에서는 camelCase(postTitle)를 사용합니다.

2. prop 타입

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

위의 코드와 같이 propsstring 배열로 정의 할 수 있습니다.

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object
}

또한 위의 코드와 같이 prop에 특정 객체 타입을 지정할 수 있습니다. 이렇게 사용하면 prop를 좀 더 구체적으로 문서화 하여 다른 사람이 코드를 보았을 때, 좀 더 이해하기 쉬운 코드가 될 수 있습니다. 뿐만 아니라, 지정된 타입 이외의 타입이 지정되면 콘솔에 경고 메시지가 출력 되기 때문에, 정상적이지 않은 prop가 넘겨진 것을 단번에 알 수도 있습니다.

3. prop에 정적, 동적 데이터 넘겨주기

<blog-post title="My journey with Vue"></blog-post>

위의 코드와 같이 prop를 통해 정적인 데이터를 넘겨 줄 수 있습니다.

<!-- Dynamically assign the value of a variable -->
<blog-post v-bind:title="post.title"></blog-post>

<!-- Dynamically assign the value of a complex expression -->
<blog-post
  v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>

또한 위의 코드와 같이 v-bind를 사용하여 동적인 데이터를 넘겨 줄 수도 있습니다. prop로 모든 값들은 전달이 가능합니다.

1) Number

<!-- Even though `42` is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string.       -->
<blog-post v-bind:likes="42"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:likes="post.likes"></blog-post>

prop로 Number 타입을 넘겨 줄 때 v-bind를 통해 직접 숫자를 넘겨 줄 경우(v-bind:likes="42" 와 같이) v-bind를 사용할 경우 자바스크립트 표현식으로 사용되기 때문에 넘겨진 숫자는 문자열이 아닌 숫자로 인식됩니다.

2) Boolean

<!-- Including the prop with no value will imply `true`. -->
<blog-post is-published></blog-post>

<!-- Even though `false` is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string.          -->
<blog-post v-bind:is-published="false"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

<blog-post is-published></blog-post>와 같이 prop를 정의하고 값을 넘겨주지 않는다면 true 값이 전달 된 것으로 인식됩니다.

3) Array

<!-- Even though the array is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string.            -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

4) Object

<!-- Even though the object is static, we need v-bind to tell Vue that -->
<!-- this is a JavaScript expression rather than a string.             -->
<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

<!-- Dynamically assign to the value of a variable. -->
<blog-post v-bind:author="post.author"></blog-post>

5) 한꺼번에 넘겨주기

v-bind:props-name을 사용하지 않고 v-bind로 값을 props로 통째로 넘겨줄 수도 있습니다.

post: {
  id: 1,
  title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>

위의 코드와 값이 v-bind로 값이 통째로 넘겨 주었다면,

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

위의 코드와 같은 동작을 하게 됩니다.

4. 단방향 데이터 흐름

컴포넌트는 부모 컴포넌트에서 자식 컴포넌트를 데이터를 보내는 단방향 데이터 흐름을 가지게 됩니다. 단방향 데이터 흐름은 자식 컴포넌트에서 부모 컴포넌트의 데이터가 변경되는 것을 막기 때문에, 어플리케이션의 데이터 흐름을 단순하게 만들 수 있습니다.

부모 컴포넌트가 업데이트 되면, 자식 컴포넌트로 넘겨주는 props 또한 업데이트 되기 때문에, 자식 컴포넌트도 부모 컴포넌트 따라 업데이트 됩니다. 그리고, 자식 컴포넌트에서 props를 수정하려고 시도 할 때 콜솔 경고를 출력 하게 됩니다.

참고 - ObjectArray 타입의 prop를 사용 할 경우 유의사항

ObjectArray를 자식 컴포넌트로 넘겨줄 때는 ObjectArray는 reference로 넘겨주기 때문에 Object, Array 형태의 prop를 자식 컴포넌트에서 변경 할 때, 부모 컴포넌트도 변경 됩니다.

자식 컴포넌트에서 부모 컴포넌트로 전달 받은 prop 값을 수정해야 할 필요가 있을 때가 있습니다.

1) prop는 초기 값으로 사용되고 이후 로컬 데이터로 사용하고 싶은 경우

위의 경우에는 prop 값을 초기 값으로 사용하는 로컬 data를 선언해야 합니다.

props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}

prop를 초기 값으로 사용해야 할 경우에는 로컬 데이터를 만들고 prop를 초기 값으로 사용합니다.

2) prop를 가공해서 사용해야 할 경우

위의 경우에는 computed 속성을 사용하여 해결 할 수 있습니다.

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

prop를 가공해서 사용해야 하는 경우, computed 속성을 사용합니다.

5. prop 유효성 체크

prop를 정의 할 때, 몇가지의 요구사항을 체크 할 수 있습니다. 정의 한 요구사항이 만족하지 않을 경우 콘솔 경고를 출력하게 됩니다. 코드를 만든 당사자가 아닌 다른 사람이 컴포넌트를 수정해야 할 때, prop의 요구사항을 정의한다면 코드를 이해하는데 도움이 될 수 있습니다.

Vue.component('my-component', {
  props: {
    // Basic type check (`null` matches any type)
    propA: Number,
    // Multiple possible types
    propB: [String, Number],
    // Required string
    propC: {
      type: String,
      required: true
    },
    // Number with a default value
    propD: {
      type: Number,
      default: 100
    },
    // Object with a default value
    propE: {
      type: Object,
      // Object or array defaults must be returned from
      // a factory function
      default: function () {
        return { message: 'hello' }
      }
    },
    // Custom validator function
    propF: {
      validator: function (value) {
        // The value must match one of these strings
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

prop에 몇가지 유효성 검사를 체크할 수 있습니다.

참고 - prop의 default, validator를 사용할 때 유의 사항

prop의 유효성 검사에서 사용되는 defaultvalidator 함수는 Vue의 인스턴스가 생성되기 전에 실행 되기 때문에, defaultvalidator 함수에서는 data, computed, method 등.. 을 사용할 수 없습니다.

1) Type 체크

prop의 type 옵션으로 사용할 수 있는 몇가지 기본 타입을 제공합니다.

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

위의 8가지 타입 이외의 커스텀 타입의 유효성 체크도 가능합니다. instanceof 를 통해 타입의 유효성을 체크 합니다.

function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}
Vue.component('blog-post', {
  props: {
    author: Person
  }
})

prop의 author를 사용하여 커스텀 타입의 유효성 체크가 가능합니다. 위의 예제는 new Person으로 prop가 만들어졌는지 체크하게 됩니다.

6. Non-Prop 속성

non-prop 속성은 attribute로 전달 되었지만, 컴포넌트에서 props로 정의 되지 않은 속성을 이야기 합니다. 컴포넌트에서는 props로 정의 된 값 뿐만 아니라 임의의 attribute를 정의 해서 사용할 수 있습니다. 이 기능을 허용하면서 HTML 태그에 커스텀 속성을 추가하는 기타 다른 라이브러리와 함께 사용이 가능해 집니다.

1) 기본 속성과 바꾸기/병합하기

<input type="date" class="form-control">

bootstrap-date-input 이라는 컴포넌트가 위의 코드와 같이 정의 되어 있다고 할 때,

<bootstrap-date-input
  data-date-picker="activated"
  class="date-picker-theme-dark"
></bootstrap-date-input>

bootstrap-date-input 컴포넌트를 위의 코드와 같이 사용된다면,

  • class 속성의 form-controldate-picker-theme-dark는 병합되어, class="form-control date-picker-theme-dark"가 됩니다.
  • data-date-picker 속성은 추가 됩니다.
<input type="date" class="form-control date-picker-theme-dark" data-date-picker="activated">

위의 코드와 같이 랜더링됩니다.

class 속성와 style 속성은 부모 컴포넌트에서 자식 컴포넌트를 선언 할 때 사용된 속성와 자식 컴포넌트에서 정의 된 속성이 병합이 됩니다. 하지만 그 외의 속성은 부모 컴포넌트에서 자식 컴포넌트를 선언 할 때 사용된 값으로 대체됩니다.

<bootstrap-date-input
  type="text"
  data-date-picker="activated"
  class="date-picker-theme-dark"
></bootstrap-date-input>

예를 들어, 위의 코드와 같이 컴포넌트를 사용한다면 실제로는,

<input type="text" class="form-control date-picker-theme-dark" data-date-picker="activated">

위의 코드와 같이 랜더링 됩니다.

2) Attribute 상속 받지 않기

inheritAttrs: false로 설정한다면, 부모 컴포넌트로부터 전달 받은 Attribute가 자식 컴포넌트의 Attribute로 설정되지 않습니다.

<base-input placeholder="inherit"></base-input>

즉 위의 코드와 같이 작성된다고 해도,

Vue.component('base-input', {
  inheritAttrs: false,
  template: '<input />'
})

위의 코드와 같이 inheritAttrs: false로 정의 되어 있다면 실제 랜더링은,

<input />

위의 코드와 같이 랜더링 됩니다. 위의 코드는 CodePen에서 확인 할 수 있습니다.

inheritAttrs: false$attrs를 함께 사용한다면 선택적으로 필요한 속성만 자식 컴포넌트에 랜더링 할 수 있게 됩니다.

<div id="app">
  <base-input
    v-model="username"
    class="username-input"
    placeholder="Enter your username"
  ></base-input>
</div>
Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on:input="$emit('input', $event.target.value)"
      >
    </label>
  `
})

new Vue({
  el: '#app'
});

위의 코드는 CodePen에서 확인 할 수 있습니다.

참고

'Vue.JS' 카테고리의 다른 글

[Vue.JS] 컴포넌트 (고급:slot)  (0) 2019.01.26
[Vue.JS] 컴포넌트 (고급:Custrom Events)  (0) 2019.01.24
[Vue.JS] 컴포넌트 (기본)  (3) 2019.01.16
[Vue.JS] 폼 입력 바인딩  (0) 2018.12.15
[Vue.JS] 이벤트 핸들링  (0) 2018.12.06
댓글
공지사항
최근에 올라온 글