본문 바로가기

Vue.js

[Udemy Vue 완벽가이드 Section8] 93. "props" 소개(부모 ⇒ 자녀 통신)

<!--App.vue-->
<ul>
  <friend-contact></friend-contact>
  <friend-contact></friend-contact>
</ul>
<!--FriendContact.vue-->
<template>
  <li>
    <h2>{{ friend.name }}</h2>
    <button @click="toggleFavorite">Toggle Favorite</button>
    <button @click="toggleDetails">
      {{ detailsAreVisible ? "Hide" : "Show" }} Details
    </button>
    <ul v-if="detailsAreVisible">
      <li><strong>Phone:</strong>{{ friend.phone }}</li>
      <li><strong>Email:</strong>{{ friend.email }}</li>
    </ul>
  </li>
</template>
<script>
export default {
  data() {
    return {
      detailsAreVisible: false,
      friend: {
        id: "manuel",
        name: "Manuel Lorenz",
        phone: "0123 45678 90",
        email: "manuel@localhost.com",
      },
    };
  },
};
</script>

 

이 FriendContact에는 문제가 하나 있다.

출력하는 데이터, 즉 친구의 이름, 전화번호, 이메일 주소 등은 모두 이 FriendContact 컴포넌트 안에 저장되어있다.

그래서 똑같은 name, phone number, email이 적힌 컴포넌트가 두 개가 찍힌다.

 

우리는 지금까지 Vue앱에 필요한 데이터를 그 앱 안에 저장했다.

그러나 컴포넌트를 다룰 때는 대부분의 경우 조금 다르다. 마크업과 특정 로직이 포함된 '재사용 가능한' 컴포넌트를 만들고자 하기 때문.

 

일부 데이터는 외부(이 컴포넌트를 사용하는 앱 또는 컴포넌트)에서 받아와야한다.

지금의 경우, 메인 앱(App.vue)에서 FriendContact 컴포넌트를 사용하고 있으므로 App.vue가 된다.

<!--App.vue-->
<ul>
  <friend-contact></friend-contact>
  <friend-contact></friend-contact>
</ul>

이 메인 앱이 friend-contact 컴포넌트로 data를 전달하자.

그렇게 하면 컴포넌트를 두 번 사용할 때, 각 컴포넌트 인스턴스에 각각 다른 데이터를 사용할 수 있다.

 

첫 번째 friend-contact 컴포넌트에는 Manuel에 대한 데이터를, 두번째 컴포넌트에는 Julie에 대한 데이터를 출력시켜보자.

같은 컴포넌트를 여러번 사용할 때, 다른 데이터로 설정한다는 개념은 핵심적인 개념이고, 따라서 Vue에서는 이를 props라는 개념으로 사용할 수 있다.

 

 

# props란 무엇일까?

props는 '프로퍼티'의 줄임말로, 일종의 커스텀 HTML attribute(속성)로 생각하면 된다.

 

1/ 커스텀 HTML 요소(컴포넌트)에 원하는 데이터를 "속성명 = 데이터" 형식으로 작성

예를 들어 App.vue 파일에서 첫번 째 friend-contact 컴포넌트로 name, phone number, email address 데이터를 전달하고 싶다고 해보자.

아래와 같이 props를 작성하여 컴포넌트에 전달해보자.

<friend-contact name="Manuel Lorenz" phone-number="01234 78992" email-address="manuel@localhost.com"></friend-contact>

 

두 번째 friend-contact 컴포넌트에는 같은 속성을 입력하되, 다른 데이터를 전달해보자.

<friend-contact name="Julie Johns" phone-number="01234 78992" email-address="manuel@localhost.com"></friend-contact>

 

2/ props를 전달받는 컴포넌트 내에 'props' 프로퍼티 추가.

이렇게 props라고 불리는 속성을 컴포넌트에 설정하면, FriendContact.vue 컴포넌트 파일 내부에서 이 props들을 사용하기위해 따로 코드를 작성해야 한다.

즉, 컴포넌트 파일 내부에서 받고자 하는 props의 속성을 Vue가 인식하도록 해야한다.

이 경우, Vue가 name, phone-number, email-address를 인식하도록 하고자 한다.

 

Vue가 인식하게 하려면, props를 전달받은 컴포넌트 파일로 가서 앱 구성객체에 특정 키를 추가하면 된다. → 'props' 프로퍼티.

이 'props'프로퍼티는 가장 단순하게는 '배열'로 받는다. (배열 이외의 방법도 존재.)

<script>
export default {
  props: ['name','phoneNumber','emailAddress'],
  data() {
    return {};
  },
  },
 methods: {}
};
</script>

 

## props 프로퍼티 추가 시, camelCase 사용

props 프로퍼티에 'phone-number', 'email-address' 이렇게 dash를 쓰지 않고, phoneNumber, emailAddress 이렇게 camelCase를 쓴다.

이유는, 여기 props로 정의한 것들은 data 프로퍼티와 마찬가지로 template을 포함한 이 Vue 컴포넌트(FriendContact.vue) 전체에서 사용 가능하여 this 키워드로 이를 참조하기 쉽게 하기 위해서.

 

예를 들어, 만약 methods에서 props가 필요하다면 this.phoneNumber 이렇게 참조할 수 있다.

그렇기 때문에 dash를 쓰지 않고, 이렇게 camelCase로 쓴다.

dash를 사용하면 유효하지 않은 JavaScript 객체 프로퍼티명이 되어서 유효하지 않은 JavaScript 코드가 된다.

ex: this.phone-number ← 유효하지 않은 JS 코드.

 

** 긴 속성명을 선언할 때 obj['phone-number']와 같이 key에 따옴표를 사용하는 번거로움을 줄이기 위해, obj.phoneNumber와 같이 camelCase를 사용한다. 이렇게 선언된 속성명은 유효한 JavaScript 식별자이며, template 표현식에서 바로 참조해서 사용할 수 있다.

따라서 컴포넌트의 프로퍼티는 camelCase로 정의해야 한다.

 

Vue는 이런 식으로 정의된 props를 자동으로 해석하여 dash가 있는 kebab-case 버전으로 바꿔준다.

 

## props 전달 시, kebab-case 사용

HTML 템플릿에서는 props를 자식 컴포넌트에 전달할 때 camelCase를 사용할 수도 있다(DOM 템플릿 제외). 

그러나 camelCase로 선언된 props 속성일지라도, 관례적으로 HTML 속성 표기법과 동일하게 kebab-case로 표기해서 사용하도록 해야한다.

<friend-contact 
 phone-number="01234 78992" // ok
 phoneNumber="01234 78992" // 이것도 ok. 하지만 관례적으로 kebab-case로 사용
 >
</friend-contact>

정리하면,

HTML 코드는 props에 kebab-case 사용,

컴포넌트가 받는 props를 정의할 때는 camelCase 사용.

 

 

 

이제 우리는 Vue에 friend-contact 컴포넌트가 3가지의 props(세가지 커스텀 속성)를 받게 된다고 알려준 셈이다.

이제 컴포넌트 내부, 즉 FriendContact.vue 컴포넌트 파일에서 이 name, phoneNumber, emailAddress props를 활용할 수 있다.

data 프로퍼티 등과 마찬가지로 JS 코드 내에서 this를 사용하여 여러 프로퍼티에 액세스 할 수 있다.

물론, template에서도 사용할 수 있다.

 

props로 받은 name을 출력해보겠다. props.name 또는 this.name이 아닌, 그냥 name으로 출력할 수 있다.

<h2>{{ name }}</h2> <!--props로 받은 name 출력-->
<button @click="toggleDetails">
  {{ detailsAreVisible ? "Hide" : "Show" }} Details
</button>

따라서, 무언가를 props로 정의했다면 그것과 동일한 이름을 data 프로퍼티나 computed 프로퍼티로 사용하면 안된다.

 

 

이렇게, 컴포넌트는 두 번 반복되지만, 각 컴포넌트가 독립적으로 작동하고 자신만의 데이터를 가지게 된다.

이를 통해 왜 컴포넌트가 Vue 및 프로그래밍 전반에 있어서 유용한 개념인지 알 수 있다.

컴포넌트에 대해 마크업과 로직을 한번만 정의하면, 다른 컴포넌트나 메인 앱에서 다양한 데이터를 가지고 필요한만큼 사용할 수 있다.

 

 

** 출처: 모든 내용은 Udemy Vue-완벽가이드 강의를 기반으로 작성하였습니다.