Props 선언
Vue components require explicit props declaration so that Vue knows what external props passed to the component should be treated as fallthrough attributes
Vue 컴포넌트는 컴포넌트에 전달된 외부의 props가 fallthrough 어트리뷰트로 처리되어야 한다는 것을 Vue가 알 수 있도록 명시적인 props 선언이 필요하다.
<script setup>을 사용하는 SFC에서는, props는 defineProps() 매크로를 사용해서 선언한다:
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>
<scipr tsetup>이 아닌 컴포넌트에서 props는 props 옵션을 사용해서 선언된다:
export default {
props: ['foo'],
setup(props) {
// setup() 은 첫번쨰 아규먼트로 props를 받는다.
console.log(props.foo)
}
}
definePorps()로 넘겨지는 아규먼트는 props options에 제공되는 값과 같다: 같은 props 옵션 API는 두개의 선언된 스타일에서 공유된다.
문자열 배열로 props를 선언하는것 외에도, 객체 문법을 사용할 수 있다:
// in <script setup>
defineProps({
title: String,
likes: Number
})
// in non-<script setup>
export default {
props: {
title: String,
like: Number
}
}
객체 선언 문법의 각각의 프로퍼티에서, 키는 prop의 이름이다, 반면 값은 기대되는 타입의 생성자 함수가 될 수 있다.
컴포넌트 편집창 뿐만 아니라, 브라우저 콘솔에서 컴포넌트를 사용하는 다른 개발자가 잘못된 타입을 넘기면 경고할 것이다. 좀 더 상세한 내용은 이 페이지의 아래쪽인 prop validation에서 다룬다.
<script setup>과 타입스크립트를 사용한다면, 순수한 타입 어노테이션을 사용한 props 선언도 가능하다:
<script setup lang="ts"
defineProps<{
title?: string
likes?: number
}>()
</script>
좀 더 상세 내용은 Typeing Component Props
Props 패싱 상세
Prop 이름 Casing
긴 이름의 prop은 camelCase를 사용해서 선언하는데, 프로퍼티 키로 따옴표를 사용하는걸 피하게 해주기 때문이며, 템플릿 표현식에서 직접적으로 참조할 수 있게 해주는데, 유효한 자바스크립트 식별자이기 때문이다.
defineProps({
greetingMessage: String
})
<span>{{ greetingMessage }}</span>
기술적으로, 자식컴포넌트로 props를 보낼때 또한 camelCase를 쓸 수 있다(DOM templates는 제외). 하지만, 컨벤션은 HTML 어트리뷰트에 배정하는 모든 cases는 kebab-case를 사용해야 한다는 것이다.
<MyComponent greeting-message="hello" />
컴포넌트 태그로 PascalCase를 사용하는 것도 가능하다. 왜냐면 네이티브 엘리먼트로 부터 구별하는 뷰 컴포넌트에 의해 템플릿 가독성이 향상되었기 떄문이다. 하지만, props를 넘길 때 camleCase를 사용하는 것보다 실용적인 이점이 없다. 그래서 각 언어의 편의성을 따르기로 결정했다.
정적인(Static) vs 동적인(Dynamic) Props
지금까지, 정적인 값으로 넘겨지는 props를 봐왔다. 이렇게:
<BlogPost title="My journey with Vue" />
v-bond나 그 단축어인 : 를 사용한 동적으로 할당된 props로 봐왔다. 이렇게 :
<!-- 동적으로 할당된 변수의 값 -->
<BlogPost :title="post.title" />
<!-- 동적으로 할당된 복잡한 표현식의 값 -->
<BlogPost :title="post.title + ' by ' + post.author.name" />
다른 타입의 값 넘기기
위의 두 예제에서 우리는 문자열 값을 넘겼지만, prop에는 모든 타입의 값이 넘겨질 수 있다.
Number
<!-- 42가 정적이지만, 뷰에 알려주기위해 v-bind를 써야한다 -->
<!-- 문자열이 아닌 자바스크립트 식이기 때문이다. -->
<BlogPost :likes="42" />
<!-- 변수의 값을 동적으로 할당한다. -->
<BlogPost :likes="post.likes" />
Boolean
<!-- 값 없이 prop을 포함하면 'true'를 암시한다. -->
<BlogPost is-published />
<!-- 'false'로 고정되어 있어도, 뷰에 알려주기 위해 v-bind가 필요하다 -->
<!--문자열이 아닌 자바스크립트 표현식이기 때문이다. -->
<BlogPost :is-published="false" />
<!-- 변수의 값을 동적으로 할당한다 -->
<BlogPost :is-published="post.isPublished" />
Arrray
<!-- v-bind 필요 -->
<BlogPost :comment-ids="[234, 266, 273]" />
<BlogPost :comment-ids="post.commentIds" />
Obejct
<BlogPost
:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
/>
<BlogPost :author="post.author" />
객체를 사용하여 여러개의 프로퍼티 바인딩하기
만약 props로 객체의 전체 프로퍼티들을 넘기길 원하면, 아규먼트 없이 v-bind를 사용할 수 있다( :prop-name 대신에 v-bind). 에를들어, post 객체가 주어졌다:
const post = {
id: 1,
title: 'My Journey with Vue'
}
템플릿은 다음과 같다:
<BlogPost v-bind="post" />
이것과 동일하다:
<BlogPost :id="post.id" :title="post.title" />
단방향 데이터 흐름
모든 props는 자식 컴포넌트와 부모컴포넌트 사이에 단방향 바인딩을 형성한다: 부모 프로퍼티가 업데이트 되었을 때, 자식에게 흘러가지만, 반대 방향은 아니다. 자식컴포넌트가 부모의 상태를 뜻하지않게 상태변화 시키는걸 막아준다. 그래서 이해하기 어려운 앱의 데이터의 흐름을 만들 수도 있는걸 막아준다.
부모컴포넌트가 업데이트 된 매 순간, 자식 컴포넌트의 모든 props는 최근 값으로 새로고침 될 것이다. 자식 컴포넌트 안에 prop을 상태변화하려고 시도할 필요가 없음을 의미한다. 만약 그렇게 시도하면, 뷰는 콘솔에 경고할 것이다.
const props = defineProps(['foo'])
// warning, props are readonly!
props.foo = 'bar'
prop을 상태변화시키고 싶은 유혹에 빠지는 두 가지 경우가 있다.
1. 초기값을 넘기기위해 사용되는 prop 이다. 자식 컴포넌트는 나중에 지역 데이터 프로퍼티를 사용하기를 원한다. 이 경우에, 초기값으로 prop을 사용한 지역 데이터 프로퍼티를 정의하는게 최선이다:
const props = defineProps(['initialCounter'])
// counter는 오직 props를 사용한다. 초기값으로서 initialCounter를 사용한다;
// 미래의 prop 업데이트로부터 연결이 끊어진다.
const counter = ref(props.initialCounter)
2. 바뀔 필요가있는 줄값으로서 넘겨지는 prop이다. 이 경우에, prop.의 값으로 computed 프로퍼티를 정의하는게 베스트다:
const props = defineProps(['size'])
// computed property는 prop이 바꼈을 때 자동으로 업데이트 된다
const normalizedSize = computed(() => props.size.trim().toLowerCase())
객체와 배열 Prop의 상태변화
객체와 배열이 props로 넘겨졌을 때, 자식 컴포넌트는 prop 바인딩을 상태변화할 수 없지만, 객체나 배열의 중첩프로퍼티는 상태변화할 수 있습니다. 왜냐하면 자바스크립트 객체와 배열이 참조값으로 넘겨지기 때문이고, 뷰가 이런 상태변화를 막는데 비합리적으로 비싸기 때문입니다.
이런 상태변화의 큰 결점은 부모 컴포넌트에게 명확하지 않은 방법으로 부모컴포넌트의 상태를 자식컴포넌트가 영향을 줄 수 있는것이며, 잠재적으로 향후 데이터 흐름을 어렵게 만듭니다. best practice로, 디자인을 통해 강력하게 결합된 부모 자식의 상태변화를 피하는 것입니다. 대부분의 경우, 자식은 부모가 상태변화를 수행하도록 이벤트를 내보낼(emit an event) 수 있습니다.
Prop 유효성 검사
컴포넌트들은 그들의 props를 위한 특별한 자격요건을 걸 수 있습니다. 예를들면, 전에 살펴본 타입같은 것입니다. 만약 자격조건을 만나지 않았다면, 뷰는 브라우저의 자바스크립트 콘솔에서 경고할 것입니다. 다른데서 사용되는 컴포넌트를 개발할 때 특히 유용합니다.
prop의 유효성을 특정하기 위해, 문자열 배열 대신에 defineProps() 매크로로 유효성 조건의 객체를 제공할 수 있습니다. 예를들면:
defineProps({
// 기본적인 타입 체크
// ('null' 과 'undefined' 값은 모든 타입이 가능하다)
propA: Number,
// 여러개의 타입도 가능하다
propB: [String, Number].
// string이 필요하다
propC: {
type: String,
required: true
},
// default 값 Number
propD: {
type: Number,
default: 100
},
// default 값 객체
propE: {
type: Object,
// 객체나 배열의 기본값은 factory 함수에서
// 리턴돼야 한다.
default() {
return { message: 'hello' }
}
},
// 커스텀 유효성 함수
propF: {
validator(value) {
// 값은 이 문자열중 하나로 매칭돼야 한다.
return ['success', 'warning', 'danger'].includes(value)
}
},
// default값과 함수
propG: {
type: Function,
// 오브젝트나 배열의 default와 다르게,
// fcatory 함수가 아니다.
// default값으로서 함수를 준다.
default() {
return 'Default function'
}
}
})
팁 defineProps() 아규먼트에 들어간 코드는 <script setup>에 선언된 다른 변수가 접근할 수 없다, 오냐면 전체 표현식이 컴파일 됐을 때 바깥 함수 범위로 옮겨졌기 때문이다. |
추가 정보:
- 모든 props는 기본적으로 Optional이다, required: true로 특정하지 않는이상.
- 누락된 optional prop은 indefined 값을 가진다.
- default값이 특정되면, 리졸브된 prop 값이 undefuned일 때 사용된다 - prop이 누락일 때와 명백히 undefined 값이 넘겨져올때 둘 다 적용된다.
prop 유효성검사가 실패하면 뷰는 콘솔 경고를 생성한다 ( 개발자 빌드를 사용했을 때).
만약 타입에 기반을 둔 props 선언을 사용하면, 뷰는 런타임 prop 선언과 동일하게 타입 애노테이션을 컴파일 한다. 예를 들면, defineProps<{ msg: string }>은 { msg: { type: String, required: true }}로 컴파일 된다.
런타임 타입 체크
type은 다음과 같은 네이티브 생성자 중 하나가 될 수 있다:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
type은 커스텀 클래스나 생성자 함수 그리고 instanceof 체크로 만들어진 assertion도 될 수 있다. 예를들면, 다음과같은 클래스가 주어진다:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
prop의 타입으로 사용할 수 있다.
defineProps({
author: Person
})
new Person으로 만들어진 author prop의 값이 유효성 검사 된다.
Boolean 캐스팅
Boolean 타입의 Props는 네이티브 불린 어트리뷰트의 기능을 흉내내기 위해 특별한 캐스팅 룰을 가진다. 다음의 선언과 주어진 <MyComponent>가 있다.
defineProps({
disabled: Boolean
})
컴포넌트는 이렇게 사용된다:
<!-- :disabled="true"를 넘기는 것과 동일 -->
<MyComponent disabled />
<!-- :disabled="false"를 넘기는 것과 동일 -->
<MyComponent />
여러개의 타입을 허용하도록 선언된 prop일 때는 다음과 같다.
defineProps({
disabled: [Boolean, Number]
})
Boolean을 위한 캐스팅 규칙은 타입이 나오는 순서에 관계없이 적용된다.
'front > vue' 카테고리의 다른 글
[뷰3 공식문서 번역] 반응형 심화 Reactivity in Depth (0) | 2022.05.03 |
---|---|
[vue3 공식문서 번역]Components.3.Events (0) | 2022.04.29 |
[vue3 공식문서 번역]Components.1.Registration (0) | 2022.04.28 |
[vue3 공식문서 번역]Essentials.13.Components Basics (0) | 2022.04.28 |
[vue3 공식문서 번역]Essentials.12.Template Refs (0) | 2022.04.27 |
댓글