본문 바로가기

Vue.js

[Udemy Vue 완벽가이드 Section8] 101. 데모: 컴포넌트 추가 및 연결하기

컴포넌트, props, 커스텀 이벤트에 대해 많이 공부하였다.

props는 컴포넌트에 데이터를 '보내기' 위해, 이벤트는 컴포넌트로부터 데이터를 '내보내기'위해 존재한다는게 핵심 포인트.

 

App.vue 파일에서 friends 데이터 프로퍼티는 정적이다. 친구 두명의 배열인데다, isFavorite을 변경할 수는 있지만 친구를 추가하거나 삭제할 수는 없다.

 

 

# 동적으로 friend 추가하기

먼저 name, phonenumber, emailaddress 등의 friend 데이터를 입력할 새 컴포넌트를 만들어보자. 그리고 해당 데이터를 확정하고, friends 데이터 프로퍼티에 추가해보자.

 

많은 로직이 포함된 큰 Vue 파일 대신, 더 작게 쪼개진 특화된 컴포넌트를 만들고 그 컴포넌트를 조합하여 UI를 구축하는 것이 이상적이다.

그래서 App.vue에 friend 데이터를 입력할 form 태그를 추가하는 것이 아니라, components 폴더에 새 컴포넌트 NewFriend.vue를 만들어보자.

 

이 NewFriend.vue 컴포넌트에 form을 생성하고, 사용자 입력을 처리하자.

그리고 입력이 confirm된 후, App.vue 파일(부모 컴포넌트)로 향하는 커스텀 이벤트를 emit하여 입력된 데이터를 App.vue에 전달하자.

 

//NewFriend.vue 컴포넌트
<template>
  <form @submit.prevent="submitData"> <!--양식 제출 시, submitData메서드가 트리거된다.-->
    <div>
      <label for="">Name</label>
      <input type="text" v-model="enteredName" />
    </div>
    <div>
      <label for="">Phone</label>
      <input type="tel" v-model="enteredPhone" />
    </div>
    <div>
      <label for="">E-mail</label>
      <input type="email" v-model="enteredEmail" />
    </div>
    <div>
      <button>Add Contact</button>
    </div>
  </form>
</template>
<script>
export default {
  emits: ["add-contact"], //이벤트명을 직관적을 표현. 어떤 이름을 써도 ok.
  data() {
    return {
      enteredName: "",
      enteredPhone: "",
      enteredEmail: "",
    };
  },
  methods: {
    submitData() {
      this.$emit(
        "add-contact",
        this.enteredName,
        this.enteredPhone,
        this.enteredEmail
      );
    },
  },
};
</script>

 

Add Contact 버튼은 form 내부에 있으므로, button을 클릭하면 form 양식이 제출된다.

(따라서 button에 @click="" 이렇게 이벤트리스너를 바인딩할 필요 없다.)

 

main.js에서 NewFriend 컴포넌트를 import한다. 그리고 component 메서드를 통해 이 NewFriend 컴포넌트를 등록한다.

import { createApp } from "vue";

import App from "./App.vue";
import NewFriend from "./components/NewFriend";

const app = createApp(App);

app.component("new-friend", NewFriend);

app.mount("#app");

 

new-friend는 커스텀 HTML 태그가 된다. 단어 사이에 대시(-)가 들어가는 두 단어(kebab-case)로 이루어진 태그여야한다.

 

 

그럼, NewFriend에 props는 어떤게 필요할까?

필요한게 없다. 왜냐하면 이 컴포넌트는 오히려 사용자 데이터를 수집하여 App.vue에 전달하는 역할을 하는데, 딱히 외부 데이터를 받아올 필요가 없다. 그래서 지금은 props가 없어도 된다.

하지만, event는 꼭 발생시켜야 한다. 그러니 emits 프로퍼티를 추가해서 이벤트 이름을 지어서 넣어주자.

emits: ['add-contact']

 

 

form에 @submit으로 양식제출 이벤트를 수신하도록 한다. prevent 수식어를 사용하여 양식을 제출할 때 페이지가 새로고침되는 브라우저 기본동작을 방지한다.

<form @submit.prevent="submitData">

 

 

커스텀 이벤트를 수신하는 대상에 해당 데이터(friend에 대해 입력한 데이터들)를 전달할 수 있도록 add-contact 이벤트를 emit하자. 수신대상은 부모 컴포넌트인 App.vue가 된다. 

emit 시 데이터를 같이 보낼 때, 하나의 객체로 그룹화하여 하나의 인수로 만들어 전달할 수도 있고, 지금처럼 세 개의 인수로 전달할 수도 있다.

  methods: {
    submitData() {
      this.$emit("add-contact", this.enteredName, this.enteredPhone, this.enteredEmail);
      //this.$emit("add-contact", { name: this.enteredName, phone: this.enteredPhone, email: this.enteredEmail });
    },
  },

 

App.vue에서 이 add-contact 커스텀 이벤트를 수신하게 만들자. 그리고 add-contact 이벤트를 수신할 시, 트리거되는 addContact 메서드를 바인딩하자. (이벤트명과 메서드를 동일하게 할 필요는 없다.)

<new-friend @add-contact="addContact"></new-friend>

 

addContact 메서드는 매개변수 3개를 가진다.

addContact(name, phone, email) { //매개변수명은 마음대로 지어도 되지만, 순서는 바뀌면 안된다. 이벤트를 발생시킬 때의 순서와 같아야한다.
 const newFriendContact = {
  id: new Date().toISOString(), // 가상 고유 id를 생성. JS에서 얻을 수 있는 현재 날짜. 현재 타임스탬프를 나타내는 문자열로 변환.
  //완전히 고유하다곤 할 수 없지만, 적어도 지금은 이걸로 충분.
  name: name, // 프로퍼티명은 friends 배열의 객체 요소와 같아야한다.
  phone: phone,
  email: email,
  isFavorite: false,
 };
 this.friends.push(newFriendContact);
};

 

 

이렇게 NewFriend.vue라는 새 컴포넌트를 통해 새 연락처를 추가할 수 있게 되었다.

 

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