[Vue.js 기초] components, props

지은·2023년 9월 24일
0

✅ Vue.js

목록 보기
3/3

* 이 글은 SFC(싱글 파일 컴포넌트) 문법을 사용합니다.

싱글 파일 컴포넌트의 <script> 태그 안에는 다양한 속성이 있을 수 있으며, 이러한 속성들을 활용해 Vue 컴포넌트를 정의하고 데이터와 로직을 관리할 수 있다.
그 중 가장 일반적으로 사용되는 다음 다섯 가지의 주요 속성에 대해 알아보자.

  1. components : 다른 Vue 컴포넌트를 해당 컴포넌트 내에서 사용할 때 등록하는 속성
  2. props : 부모 컴포넌트로부터 데이터를 받아오는 속성
  3. data() : 컴포넌트 내에서 사용할 데이터를 정의하는 속성
  4. methods : 컴포넌트 내에서 사용할 메소드(함수)를 정의하는 속성
  5. computed : data, props를 기반으로 계산된 값을 반환하는 속성

1. components

: Vue 컴포넌트 내에서 다른 Vue 컴포넌트를 사용하는 데 사용되는 속성

컴포넌트 사용하기

아래와 같이 ButtonCounter 라는 컴포넌트가 있다.

// ButtonCounter.vue
<template>
  <button @click="count++">당신은 {{ count }} 번 클릭했습니다.</button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<style>
</style>

이 컴포넌트를 부모 컴포넌트에서 사용하고 싶다면,

  1. <script> 태그 안에서 해당 컴포넌트를 import하고,
  2. components 옵션을 사용해서 등록해야 한다.
    (리액트는 컴포넌트를 import해서 바로 사용할 수 있지만, 뷰에서는 등록이 필요하다.)

컴포넌트 이름 표기법은 PascalCase를 사용해도 되고, kebab-case를 사용해도 된다.

// App.vue
<template>
  <h1>아래에 자식 컴포넌트가 있습니다.</h1>
  <ButtonCounter />  // PascalCase
  <button-counter /> // kebab-case
</template>

<script>
import ButtonCounter from './ButtonCounter.vue' // 컴포넌트 import

export default {
  components: {
    ButtonCounter // 등록
    // 'my-button-counter': ButtonCounter 👈 케밥 케이스 & 컴포넌트명 변경 가능
  }
}
</script>

<style>
</style>
  • 이 속성을 통해 부모 컴포넌트 내에서 자식 컴포넌트를 사용할 수 있게 되며, 컴포넌트 간의 재사용성을 높이고 모듈화된 코드를 작성할 수 있다.
  • components 속성 안에 등록한 컴포넌트는 로컬 컴포넌트이기 때문에, 현재 컴포넌트에서만 사용할 수 있고 전역 컴포넌트와 달리 다른 컴포넌트에서 충돌할 위험이 적다.

2. props

: 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용하는 속성

만약 <Blog>라는 부모 컴포넌트에서 <BlogPost>라는 자식 컴포넌트로 idtitle를 props를 전달해주어 <BlogPost>를 렌더링한다고 가정해보면 아래와 같이 작성할 수 있다.

부모 컴포넌트에서 Props 전달하기

// Blog.vue
<template>
  <blog-post id="1" title="Vue와 함께한 나의 여행" /> // 자식 컴포넌트
</template>

<script>
import BlogPost from './BlogPost.vue'

export default {
  components: {
    'blog-post': BlogPost,
  }
}
</script>

<style>
</style>

자식 컴포넌트에서 Props 받기

자식 컴포넌트에서 전달받은 props를 사용하려면 props 속성 내에 전달받으려는 props를 프로퍼티 이름: 데이터 타입 형식으로 정의해야 한다.

  • 이렇게 전달받은 props는 다른 속성처럼 템플릿 내에서 사용할 수 있고, 컴포넌트의 this 컨택스트에서 접근할 수도 있다. (this.id, this.title로 접근 가능)
// BlogPost.vue
<template>
  <h4>{{ title }}</h4> // 템플릿 내에서 사용
</template>

<script>
export default {
  props: {
    // 프로퍼티 이름: 데이터 타입
    id: Number,
    title: String,
  }
}
</script>

<style>
</style>
  • 유효성 검사기본값(default value)을 설정할 수도 있다.
<script>
export default {
  props: {
    id: { type: Number, required: true },    // 유효성 검사
    title: { type: String, default: '무제' }, // 기본값
  }
}
</script>

하지만 보통은 위의 예시처럼 idtitle을 하드코딩해서 전달해주기 보다 부모 컴포넌트에 있는 데이터를 동적으로 전달해주는 경우가 많다.
부모 컴포넌트에 아래와 같은 배열이 있고, <BlogPost> 컴포넌트를 여러 개 렌더링해야 한다면 어떻게 해야할까?

posts: [
        { id: 1, title: 'Vue와 함께한 나의 여행' },
        { id: 2, title: 'Vue로 블로깅하기' },
        { id: 3, title: 'Vue가 재미있는 이유' }
        // ...(200개)
      ]

동적으로 Props 전달 (v-bind) & 배열 렌더링 (v-for)

리액트에서는 map() 메소드를 사용하지만, 뷰에서는 v-for 디렉티브를 사용한다.

v-for

: Vue.js에서 반복문을 처리하고 템플릿(HTML)을 렌더링하는 데 사용되는 디렉티브

<ul>
  <li v-for="(item, index) in items" key="item.id">{{ index }}. {{ item }}</li>
</ul>

map() 메소드를 사용할 때와 마찬가지로 v-for 디렉티브를 사용할 때는 Vue.js가 렌더링되는 각 요소(list item)들을 구별하고 어떤 요소가 변경되었는지 확인하여 효율적으로 렌더링을 수행할 수 있도록 고유한 key 속성을 지정해줘야 한다.

v-bind

: Vue 데이터와 HTML 요소의 속성/프로퍼티를 동적으로 연결(binding)하는 디렉티브
데이터가 변경되면 화면이 동적으로 업데이트되도록 해준다.

<button :disabled="isButtonDisabled">버튼</button>
// Blog.vue
<template>
  <div>
    <h1>블로그 포스트</h1>
      <BlogPost 
        v-for="post in posts"
        :key="post.id" 
        :post="post" // v-bind의 단축 문법 (:)
      />
  </div>
</template>

<script>
import BlogPost from './BlogPost.vue';

export default {
  data() {
    return {
      posts: [
        { id: 1, title: 'Vue와 함께한 나의 여행' },
        { id: 2, title: 'Vue로 블로깅하기' },
        { id: 3, title: 'Vue가 재미있는 이유' }
      ]
    };
  },
  components: {
    'blog-post': BlogPost,
  }
};
</script>

그리고 자식 컴포넌트에서는 post 자체를 객체로 받아와 사용할 수도 있다.

// BlogPost.vue
<template>
  <div>
    <h2>{{ post.title }}</h2>
  </div>
</template>

<script>
export default {
  props: {
    post: { type: Object, required: true }
  }
};
</script>
profile
개발 공부 기록 블로그

0개의 댓글