From 65c473a31e2458a44cf2de401f60a52117042111 Mon Sep 17 00:00:00 2001 From: bgchoi Date: Thu, 13 Jun 2019 01:17:11 +0900 Subject: [PATCH] Create components-props.md --- src/v2/guide/components-props.md | 347 +++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 src/v2/guide/components-props.md diff --git a/src/v2/guide/components-props.md b/src/v2/guide/components-props.md new file mode 100644 index 0000000000..557464640e --- /dev/null +++ b/src/v2/guide/components-props.md @@ -0,0 +1,347 @@ +--- +title: props +type: guide +order: 102 +--- + +> 이 페이지는 여러분이 이미 [컴포넌트 기초](components.html)를 읽었다고 가정하고 쓴 내용입니다. 컴포넌트가 처음이라면 기초 문서를 먼저 읽으시기 바랍니다. +> (역자 주: 아래 문서는 컴포넌트의 옵션 중 하나인 `props`를 다루고 있습니다. 해당 옵션은 'props'로 표기하고 property는 속성으로, prop은 때에 따라 props의 요소 혹은 속성으로 번역했습니다.) + +## props의 표기법 (카멜표기법 vs 케밥표기법) + +HTML 인자의 이름들은 대소문자를 가리지 않습니다. 브라우저가 모든 대문자를 소문자로 변환하기 때문입니다. 'in-DOM 템플릿'을 사용할 때 카멜표기법 방식의 props의 표기를 케밥표기법(하이픈으로 단어를 구분하는 표기법)으로 바꿔야 하는 이유입니다. + +```js +Vue.component("blog-post", { + // 자바스크립트에서는 카멜표기법(postTitle) 사용 + props: ["postTitle"], + template: "

{{ postTitle }}

" +}); +``` + +```html + + +``` + +하지만 문자 템플릿을 사용한다면 이 제한이 적용되지 않습니다. + +## props의 타입 + +이제까지는 아래와 같이 주로 문자 배열로 된 props를 살펴봤습니다. + +```js +props: ["title", "likes", "isPublished", "commentIds", "author"]; +``` + +보통은 props의 각 요소 별로 특정한 타입이 필요합니다. 그럴 경우에는 props 각 요소의 이름과 타입을 함께 저장하는 객체 방식을 사용할 수 있습니다. + +```js +props: { + title: String, + likes: Number, + isPublished: Boolean, + commentIds: Array, + author: Object, + callback: Function, + contactsPromise: Promise // 다른 생성자 사용 가능 +} +``` + +이를 통해 컴포넌트를 문서화할 뿐만 아니라 브라우저의 자바스크립트 콘솔 사용자들이 잘못된 타입을 사용했을 때 경고를 줄 수 있습니다. [타입 확인과 다른 props 검증](#props-검증)에 대해서는 아래쪽에서 더 다룰 것입니다. + +## 고정된 props와 가변적인 props를 전달하는 방법 + +이제까지는 아래와 같이 고정된 값을 props로 넘기는 사례들을 살펴봤습니다. + +```html + +``` + +하지만 아래와 같이 `v-bind`를 이용해서 가변적으로 props를 정하는 것도 가능합니다. + +```html + + + + + +``` + +위의 두 사례에서는 문자를 이용했지만 _어떤_ 타입의 값도 props에 사용할 수 있습니다. + +### 숫자 이용하기 + +```html + + + + + + +``` + +### 불리언 이용하기 + +```html + + + + + + + + + +``` + +### 배열 이용하기 + +```html + + + + + + +``` + +### 객체 이용하기 + +```html + + + + + + +``` + +### 객체의 구성요소 이용하기 + +객체의 모든 구성요소(property)들을 props로 전달하려면 인수가 없는 `v-bind`(즉 `v-bind:prop-name` 대신 `v-bind`)를 이용할 수 있습니다. `post` 객체의 예를 살펴봅시다. + +```js +post: { + id: 1, + title: 'My Journey with Vue' +} +``` + +템플릿이 아래와 같으면 + +```html + +``` + +아래와 같은 결과가 나옵니다. + +```html + +``` + +## 단방향 데이터 흐름 + +모든 props의 데이터들은 자식 컴포넌트의 속성과 부모 컴포넌트의 속성 사이에서 **단방향 바인딩**을 형성합니다. 부모 컴포넌트의 속성이 업데이트되면 하위로 흐르게 되지만 그 반대는 안됩니다. 이렇게하면 자식 컴포넌트가 실수로 부모 컴포넌트의 상태를 변경하여 앱의 데이터 흐름을 이해하기 어렵게 만드는 것을 방지할 수 있습니다. + +그리고 부모 컴포넌트가 업데이트 될 떄마다 자식 컴포넌트의 모든 속성들이 최신값으로 갱신됩니다. 즉 자식 컴포넌트의 속성들을 굳이 변경시킬 필요가 **없는** 겁니다. 만약 사용자가 그렇게 하면 Vue에서 콘솔을 통해 경고를 줄 것입니다. + +일반적으로 (역자 주: 상위 컴포넌트의 속성이 바뀌었을 때 하위) 컴포넌트의 속성을 변경시켜야 하는가 싶을 때가 두 가지 있습니다. + +1. **그 속성이 초기값을 전달할 때 사용되며 자식 컴포넌트는 이를 받아서 로컬 데이터 속성으로 이용하는 경우.** 이 경우에는 자식 컴포넌트에 로컬 데이터 속성을 따로 정의하고 전달받는 속성은 초기값으로만 쓰는 것이 좋습니다.(역자 주: 즉 이후에 전달받은 속성을 따로 업데이트할 필요 없습니다.) + +```js +props: ['initialCounter'], +data: function () { + return { + counter: this.initialCounter + } +} +``` + +2. **전달된 속성을 그대로 쓰는 것이 아니라 적절하게 가공해서 사용할 떄.** 이 경우에는 전달된 속성의 값을 이용해서 computed 속성을 정의해놓는 것이 좋습니다.(역자 주: 즉 알아서 업데이트 되니까 신경쓰지 않아도 됩니다.) + +```js +props: ['size'], +computed: { + normalizedSize: function () { + return this.size.trim().toLowerCase() + } +} +``` + +

자바스크립트의 객체와 배열은 참조로 전달되므로 전달되는 속성이 배열이나 객체인 경우 자식 컴포넌트의 객체 또는 배열 자체를 변경하면 부모 컴포넌트의 데이터에 **영향을 줍니다**.

+ +## props 검증 + +컴포넌트가 props에 대해서 앞에서 봤던 타입 등 구체적인 조건을 지정할 수도 있습니다. 조건이 맞지 않으면 Vue에서 브라우저의 자바스크립트 콘솔을 통해 사용자에게 경고를 보낼 것입니다. 이 기능은 다양한 사람들이 사용할 컴포넌트를 만들 때 특히 유용합니다. + +props에 대한 검증 조건을 구체화하기 위해 각 props의 값에 대한 검증 조건을 객체 형태로 제시할 수 있습니다. 아래의 예를 살펴봅시다. + +```js +Vue.component("my-component", { + props: { + // 기본적인 타입 확인 (`null`, `undefined`는 어떤 타입 검증도 통과합니다.) + propA: Number, + // 복수의 타입이 가능한 경우 + propB: [String, Number], + // 문자 타입이며 필수값 + propC: { + type: String, + required: true + }, + // 기본값이 있는 숫자 타입 + propD: { + type: Number, + default: 100 + }, + // 기본값이 있는 객체 타입 + propE: { + type: Object, + // 객체나 배열의 기본값은 반드시 팩토리 함수로 표현되어야 합니다. + default: function() { + return { message: "hello" }; + } + }, + // 검증 함수를 만들 수도 있습니다. + propF: { + validator: function(value) { + // value가 반드시 아래의 문자 중 하나여야 합니다. + return ["success", "warning", "danger"].indexOf(value) !== -1; + } + } + } +}); +``` + +props에 대한 검증이 실패하면 Vue가 콘솔에 경고를 날립니다.(물론 개발 모드일 때요.) + +

props에 대한 검증은 컴포넌트 인스턴스를 만들기 **전에** 진행한다는 점을 주의하세요. 인스턴스의 속성들(`data`, `computed` 등)은 그래서 `기본값`이나 `검증 함수`에 쓸 수 없습니다.

+ +### 타입 확인 + +`type`은 다음의 자바스크립트 고유 생성자들 중 하나일 수 있습니다. + +- String(문자) +- Number(숫자) +- Boolean(불리언) +- Array(배열) +- Object(객체) +- Date(날짜) +- Function(함수) +- Symbol(심벌) + +아니면 `type`이 다른 커스텀 생성자 함수일 수도 있고 `instanceof` 를 이용해서 나중에 확인할 수도 있습니다. 아래의 예에서 생성자 함수를 봅시다. + +```js +function Person(firstName, lastName) { + this.firstName = firstName; + this.lastName = lastName; +} +``` + +이렇게 이용할 수 있겠죠. + +```js +Vue.component("blog-post", { + props: { + author: Person + } +}); +``` + +`author` 속성의 값은 `new Person`을 통해서 만들어진 값입니다. + +## 속성이 아닌 인자들 + +속성이 아닌 인자란 컴포넌트로 넘겨지는 인자이긴 하지만 해당하는 정의된 속성은 없는 것을 의미합니다. + +자식 컴포넌트로 정보를 넘길 때 명시적으로 정의된 속성이 더 선호된 것은 사실이지만 컴포넌트 라이브러리를 만드는 사람들이 컴포넌트가 사용될 상황을 항상 예측할 수는 없습니다. 그래서 컴포넌트에서 컴포넌트의 루트 요소에 임의적인 인자를 추가할 수 있게 만들어 뒀습니다. + +예를 들어 `bootstrap-date-input`라는 서드파티 컴포넌트를 쓰고 있다고 생각해봅시다. 이 컴포넌트는 `input`에 `data-date-picker` 인수를 필요로 합니다. 아래와 같이 컴포넌트 인스턴스에 이 인수를 추가할 수 있죠. + +```html + +``` + +`data-date-picker="activated"` 인수는 자동으로 `bootstrap-date-input` 컴포넌트의 루트 요소에 추가됩니다. + +### 기존 인수를 대체하거나 기존 인수에 합치기 + +`bootstrap-date-input`의 템플릿을 생각해봅시다. + +```html + +``` + +날짜를 고르는 플러그인에 쓸 테마를 만들기 위해 특정한 클래스를 아래와 같이 추가할 수 있습니다. + +```html + +``` + +이 경우에 `class`에 대한 두 가지 값이 정의됩니다. + +- `form-control`, 템플릿에 있는 컴포넌트에 의해서 정해진 값 +- `date-picker-theme-dark`, 부모 컴포넌트에서 전달된 값 + +대부분의 인수들은 컴포넌트로 전달된 값이 컴포넌트에서 정해진 값을 대체합니다. 예를 들어 `type="text"`가 전달되면 `type="date"`를 대체하고 에러가 나는 거죠. 다행히도 `class`, `style` 인수는 조금 더 똑똑해서 두 값을 `form-control date-picker-theme-dark`로 합칩니다. + +### 인수 상속 금지 + +만약 컴포넌트의 루트 요소가 인수를 상속받는 걸 **금지**하고 싶다면 컴포넌트의 옵션에서 `ingeritAttrs: false`를 지정할 수 있습니다. 아래의 예를 봅시다. + +```js +Vue.component("my-component", { + inheritAttrs: false + // ... +}); +``` + +`$attrs` 인스턴스 속성과 함께 쓰면 특히 유용합니다. `$attrs` 인스턴스 속성에는 속성의 이름과 컴포넌트로 넘기는 값이 들어 있습니다. 아래의 예를 봅시다. + +```js +{ + required: true, + placeholder: 'Enter your username' +} +``` + +`inheritAttrs: false`와 `$attrs`를 사용하면 어느 요소를 어떻게 할 지를 따로 정할 수 있습니다. [베이스 컴포넌트](../style-guide/#베이스-컴포넌트-이름-매우-추천함)에 적합한 방식입니다. + +```js +Vue.component("base-input", { + inheritAttrs: false, + props: ["label", "value"], + template: ` + + ` +}); +``` + +

`inheritAttrs: false` 옵션은 `style`, `class` 요소를 통한 통합에는 영향을 미칠 수 **없습니다**.

+ +이 패턴을 통해 어느 요소가 실제로 어느 루트 요소에 있는지를 신경쓰지 않고 베이스 컴포넌트를 HTML 요소처럼 쓸 수도 있습니다. + +```html + +```