-
[Vue.js] 컴포넌트(Component), Props & EventFront-End(Web)/Vue 2021. 5. 26. 21:04반응형
이번에는 비교적 친숙한! 뷰의 컴포넌트 개념에 대해 알아보고자 한다. React와 마찬가지로 화면을 구성하는 요소이다.
현대의 모던 프레임워크들은 대부분 컴포넌트 개념을 차용하고 있기 때문에 뷰 역시 이를 기반으로 하고 있는 것 같다.
컴포넌트와 관련된 개념과 영상이 많기 때문에 포스팅 분량이 길어지고 몇 부분으로 나눠질 것 같다.
* 이 글은 캡틴판교님의 Vue.js 강의 및 블로그를 기반으로 학습한 내용을 정리하고 있습니다.
💚 Vue 컴포넌트
React와 마찬가지로 화면을 영역 단위로 쪼개서, 재사용 가능한 코드로 캡슐화하는 개념이다.
뷰에서 컴포넌트를 등록하는 방법은 2가지가 있다. 전역 등록, 지역 등록이 바로 그것들이다.
- 전역 컴포넌트
<template> <컴포넌트 이름></컴포넌트 이름> </template> // 전역 컴포넌트 Vue.component('컴포넌트 이름', { // 컴포넌트 내용 : template... });
- 지역 컴포넌트
new Vue({ el: '#app', // 지역 컴포넌트 components: { // '컴포넌트 이름': '컴포넌트 내용' 'app-footer': { template: '<footer>Footer</footer>' } } // 혹은, 변수에 담은 객체를 전달하는 방법도 있다. const anotherWay = { template: '<div>Another Way!</div>' } components: { 'another-way': anotherWay, } });
실제 개발환경에선 지역 컴포넌트의 방식을 대부분 등록한다. (전역방식은 플러그인이나, 전역에 사용되는 컴포넌트 등록에만 사용됨)
통상은, 해당 인스턴스(vue 파일) 내에서 사용할 수 있는 컴포넌트들을 components 필드에 추가하여 사용하게 된다.
* new Vue() 인스턴스는 <Root> 루트 컴포넌트와 1:1 관계이다.
💚 컴포넌트 통신 방식
컴포넌트들은 자체 격리된 고유한 데이터 유효 범위를 갖는다. 따라서, 컴포넌트 간의 데이터 통신을 위해 아래 규칙을 따른다.
- Props
상위 컴포넌트에서 하위 컴포넌트로 특정 속성값을 넘겨주는 문법이다. 기본적인 바인딩 문법으로, "v-bind" 디렉티브를 사용한다.
<template> <div id="app"> <app-header v-bind:props명="상위 컴포넌트 데이터명"></app-header> </div> </template> <script> var appHeader = { template: '<h1>{{ props명 }}</h1>', props: ['props명'], } </script>
템플릿 리터럴 문법( {{ 값 }} )을 통해서 data, props 등을 바인딩할 수 있으며, props 필드에 참조할 props명을 배열형태로 관리한다.
이렇게 전달된 props는, 부모 컴포넌트의 조작을 통해 변형되면 바인딩된 자식 컴포넌트에도 전달된다. (Reactivity)
* props 검증
다음과 같이 props에 type 검증, default 값 설정, validator 설정 등 다양한 추가동작이 가능하다.
Vue.component('example', { props: { // 기본 타입 확인 (`null` 은 어떤 타입이든 가능하다는 뜻입니다) 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) { return value > 10 } } } })
* props 작명법
html에서는 케밥 케이스(props-data), 스크립트에선 카멜 케이스(propsData)로 각각의 문법에 맞게 작성되야 올바르게 인식함
- Event Emit (Event Bus)
하위 컴포넌트에서 상위 컴포넌트로의 통신을 위해 Event Emit 문법을 활용한다. 특정 값이 아닌, 이벤트를 올려 값 수정을 유도한다.
<template> <div id="app"> <app-button v-on:이벤트명(하위 컴포넌트)="메서드명(상위 컴포넌트)"></app-button> </div> </template> <script> var appButton = { template: '<button v-on:click="passEvent">button</button>', methods: { passEvent: function() { this.$emit('이벤트명(하위 컴포넌트)', payload) } } } new Vue({ el: '#app', components: { 'app-button': appButton } methods: { '메서드명': function() { console.log('hi'); } } }) </script>
- "v-on:이벤트명" 디렉티브를 통해 특정 이벤트와 메서드를 연계할 수 있다.
- 먼저, 이벤트를 발생시킬 하위 컴포넌트에서 $emit Vue API를 통해 상위 컴포넌트로 이벤트명을 전달해준다.
- 특정 값을 넘겨주려는 경우는, $emit의 두 번째 인자부터 추가해주면 payload 필드로 값이 넘어간다.
- 이벤트를 받는 상위 컴포넌트에서는 하위 컴포넌트의 이벤트명과 상위 컴포넌트에서 동작할 메서드를 연결한다.
- 동등 레벨 컴포넌트 간의 통신방법
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Getting Started</title> </head> <body> <!-- 2) Root : v-on을 통해 받은 payload 값을, 메서드를 통해 data 최신화. 이 data를 app-header의 props로 하달 --> <div id="app"> <app-header v-bind:propsNum="num"></app-header> <app-content v-on:pass="deliverVal"></app-content> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> // 3) app-header : props 속성으로 받음 var appHeader = { template: '<div>header</div>', props: ['propsNum'] } // 1) app-content : 이벤트, $emit을 통해 값 전달. payload 활용 var appContent = { template: '<button v-on:click="passVal">pass</button>', methods: { passVal: function() { this.$emit('pass', 10); } }, } // 0) Vue 인스턴스 세팅 new Vue({ el: '#app', components: { 'app-header': appHeader, 'app-content': appContent, }, data: { num: 0, }, methods: { deliverVal: function(val) { this.num = val } }, }) </script> </body> </html>
확실히 React 컴포넌트의 문법이 Javascript 친화적이었다는 점을 느낀다.
Vue만의 독특한 문법으로 작성되어야 하며, 각각의 속성(template, data, methods) 과 이를 연동하는 디렉티브가 그렇다.
Vue 컴포넌트를 만들어보면서 느낀 점은, 확실히 협업에 장점이 있다고 느꼈다. (문법이 일관적이므로)
반대로, 컴포넌트 간의 통신을 위해 Props, Event를 교환함에 따라 명명해야 할 요소가 많다.
이 부분을 깔끔하게 해야 할 필요성을 느꼈다!!
다음 글은 Vue 프로젝트에서 SPA 라우팅을 위해 사용되는 Vue Router에 대해 작성하고자 한다.
[출처]
- Vue 공식문서 : https://kr.vuejs.org/v2/guide/instance.html
- 캡틴판교 님의 블로그 : https://joshua1988.github.io/web-development/vuejs/vuejs-tutorial-for-beginner/
반응형'Front-End(Web) > Vue' 카테고리의 다른 글
[Vue.js] Vuex - (1) Vuex 기본 (0) 2021.06.10 [Vue.js] Template 문법 (0) 2021.06.03 [Vue.js] Vue Router (0) 2021.06.02 [Vue.js] 인스턴스 (Instance), 라이프사이클(LifeCycle) (0) 2021.05.26 [Vue.js] Vue 개요 및 세팅(CLI) (0) 2021.05.10