들어가며
다시 Vue 관련해서 공부를 했다. 확실히 계속 공부하니까 Vue에도 적응이 되는 것 같다. 항상 시작이 어렵지 한번 시작하고 나면 뭐든 할 수 있다는 걸 오늘도 느낀다.
Props
props에는 각각의 props가 어떤 타입을 가져야 하는지 명시할 수 있다.
1 props: {2 name: String,3 age: Number4 isPublished: Boolean,5 commentIds: Array,6 author: Object,7 callback: Function,8 contactsPromise: Promise9 }
타입 외에도 기본값을 지정할 수 있고, 필수로 전달해야 하는 props도 정의할 수 있다. 또, validator 속성에 함수를 정의해 유효성 검사 함수를 만들 수 있다.
1 props: {2 name: {3 type: String,4 required: true5 },6 age: {7 type: Number,8 default: 10,9 validator: function(value) {10 ...11 }12 }13 }
props로 객체의 속성들을 전달할 수 있다. 만약 객체의 모든 속성을 전달하고 싶다면 v-bind 디렉티브를 사용할 수 있다.
1 <div v-bind="user"></div>
1 const App = {2 data() {3 return {4 user: {5 name: 'jeongki',6 age: 267 }8 }9 }10 }
위와 같이 작성하는 것은 아래와 같이 작성하는 것과 같다.
1 <div v-bind:name="user.name" v-bind:age="user.age"></div>
컴포넌트 내부에서 전달 받은 props를 변경할 수는 없다. 그렇기 때문에 전달 받은 props를 반응형 데이터에 저장해서 사용하거나, computed 속성을 사용한다.
Non-prop 속성
컴포넌트의 속성으로 선언되어 있지만 props나 emits에 정의되어 있지 않은 속성들을 의미한다. 이 속성들은 $attrs 객체를 사용한다.
1 <ComponentName class="className" id="idName"></ComponentName>
1 this.$attrs.class // "className"2 this.$attrs.id // "idName"
컴포넌트의 최상위 요소가 하나라면 non-prop 속성은 자동으로 최상위 요소에 상속되는데 자동 상속을 원하지 않는다면 컴포넌트 속성에 inheritAttrs: false 를 추가하면 된다.
컴포넌트 커스텀 이벤트
상위 컴포넌트에서 하위 컴포넌트로 props를 전달할 수 있고, 하위 컴포넌트에서는 상위 컴포넌트로 커스텀 이벤트를 전달할 수 있다. 커스텀 이벤트는 $emit() 함수를 사용해 상위로 전달할 수 있고, emits 라는 속성에 커스텀 이벤트의 이름을 명시적으로 등록 시키는게 좋다고 한다.
커스텀 이벤트는 검증 과정을 거칠 수 있다.
1 emits: {2 click: null,3 submit: ({ email, password }) => {4 if (email && password) {5 return true6 } else {7 console.warn('잘못된 이벤트 페이로드입니다!')8 return false9 }10 }11 }
컴포넌트에는 v-model을 사용할 수 있다. 이때는 기본값으로 modelValue 라는 값을 사용하고 컴포넌트 내부에서는 update:modelValue 를 이벤트로 사용한다. v-model에 전달인자를 넘겨서 modelValue 값을 변경할 수 있다.
1 <div v-model:foo="bar"></div>
1 $emit('update:foo', $event)
Slot
컴포넌트의 컨텐츠가 slot 태그의 위치에 들어가게 된다.
1 <Component>Text</Component>
1 <template>2 <h1>Hello</h1>3 <slot></slot>4 </template>
위와 같이 작성하면 h1 태그 아래에 Text라는 문자가 slot의 자리에 위치하게 된다. 만약 slot 태그 사이에 값을 작성하면, 컴포넌트의 컨텐츠가 없을 때 해당 값이 출력된다. slot 태그에 name 속성으로 이름을 정하고 템플릿 태그에 v-slot: {name} 형식으로 작성하면 해당하는 slot 태그에 컴포넌트의 컨텐츠가 들어가게 된다.
동적 컴포넌트
is 속성을 사용해 컴포넌트를 동적으로 렌더링 할 수 있다. 이때 컴포넌트가 변경되면 HTML 구조에서 제거되는데 잦은 토글이 발생하면 성능 이슈가 발생할 수 있다. 이때는 컴포넌트를 keep-alive 태그로 감싸서 사용하면 컴포넌트가 unmount 되지 않는다.
refs
자바스크립트에서 DOM 요소를 조회할 때 querySelector 등의 방법을 사용한다. 프로젝트의 규모가 커질수록 검색해야 할 요소가 많아지기 때문에 성능에 문제가 생길 수 있다. 이 때 ref를 사용한다. 태그에 ref 속성을 사용해 이름을 지정하고, this.\$refs.[지정한 이름] 을 사용해 요소를 참조할 수 있다.
컴포넌트에 ref 속성을 사용하게 되면 내부의 태그 요소를 참조하기 위해 this.\$refs.[지정한 이름].$el 으로 참조할 수 있다. 컴포넌트 내에 최상위 요소가 여러 개 있으면 컴포넌트 내에 참조를 원하는 요소에 ref를 사용해 이름을 지정하고 this.\$refs.[컴포넌트에 지정한 이름].$refs.[컴포넌트 내에 지정한 이름] 으로 참조할 수 있다.
정리
오늘은 뭔가 새로운 걸 많이 배운 것 같아서 어려웠던 것 같다. TIL도 점점 대충 쓰고 있는데 요즘 조금씩 피로가 쌓여서 그런 것 같다. 이제 12일부터 Vue 과제가 시작인데 지금까지 Vue 공부하면서 부족했던 부분은 과제 기간에 채울 수 있으면 좋을 것 같다.
약 9일전에 MDN 문서에 잘못된 번역이 있어서 PR을 날렸는데 오늘 메인에 머지가 됐다. 기여랄 것도 없이 딱 한 글자 수정한 거라 민망하긴 하지만 어쨌든 인생 첫 오픈 소스 기여를 했다. PR 내용이 실제 웹에 적용되기까지는 최대 이틀이 걸린다고 하는데 수정 사항 반영되면 기여하는 과정도 정리하고 싶다.
참고자료
Vue 공식문서 https://v3.ko.vuejs.org/