Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Tags more
Archives
Today
Total
관리 메뉴

백엔드 다락방

[Vue] - Components Communication(props, emit) 본문

Front-End/Vue.js

[Vue] - Components Communication(props, emit)

레벨1개발자 2023. 2. 12. 21:11

Components Communication(props, emit)

 

1. Component란?

화면의 영역을 구분하여 개발할 수 있는 뷰의 기능으로 Component를 사용하면 UI를 독립적이고 재사용이 가능하도록 분할하여 각 부분을 개별적으로 다룰 수 있게 됩니다. 때문에 Component 기반으로 화면을 개발하게 되면 코드의 재사용성이 증가하게 됩니다.

 

 

1-1. Component 사용

 부모 Component에서 자식 Component를 사용할 수 있습니다. 자식 Component를 template에 노출하기 위해서는 components 옵션을 사용하여 컴포넌트를 등록한 후 등록된 키를 사용하여 태그로 사용할 수 있습니다.

// 자식 컴포넌트
export default {
  data() {
    return {
      count: 0
    }
  },
  template: `
    <button @click="count++">
      당신은 {{ count }} 번 클릭했습니다.
    </button>`
}
// 부모 컴포넌트
import ButtonCounter from './ButtonCounter.vue'

export default {
  components: {
    // key: component 에서 key와 component의 명이 같을 ES6 문법으로 단축이 가능합니다.
    // 'ButtonCounter': ButtonCounter 와 동일
    ButtonCounter 
  }
}
<template>
  <h1>아래에 자식 컴포넌트가 있습니다.</h1>
  <ButtonCounter /> <!-- 자식 컴포넌트 사용 -->
</template>

 

 components 옵션에 등록한 컴포넌트들은 원하는 만큼 재사용이 가능하며 사용할 때마다 해당 컴포넌트의 새로운 인스턴스가 생성됩니다.

<h1부모 컴포넌트에 많은 자식 컴포넌트를 등록할 수 있습니다!</h1>
<!-- ButtonCounter 컴포넌트의 count는 독립적입니다. -->
<button-counter />
<button-counter />
<button-counter />

 

 또한 v-for 를 사용하여 각각을 자식 Component로 렌더링 하는 경우 다음과 같이 사용할 수 있습니다.

<blog-post
  v-for="post in posts"
  :key="post.id"
  :title="post.title"
 />

 

2. Components Communication - 컴포넌트 통신

컴포넌트 통신을 위해서는 다음과 같은 규칙을 따라야 합니다.

  • 상위 컴포넌트 → 하위 컴포넌트 : props (데이터 전달)
  • 하위 컴포넌트 → 상위 컴포넌트 : event (이벤트 전달)

 위와 같이 규칙을 따르지 않고 컴포넌트 통신을 하게 되면 컴포넌트 간 N방향 통신이 발생하게 되어 데이터 추적이 어려워지게 되기 때문에 규칙을 따르는 것을 추천합니다.

 

3. Props

3-1. Props를 이용한 정적 데이터 전달

 부모 Component에서 자식 Component에 props 정적 데이터의 전달은 다음과 같습니다. 

// 자식 컴포넌트
export default {
  props: {
    greetingMessage: String
  }
}
<!-- 부모 컴포넌트 --> 
<my-component 하위 컴포넌트의 프롭스 속성 이름 = "상위 컴포넌트의 데이터 이름 or 값"/>

<my-component greetingMessage="안녕!" />

 

3-2. Props를 이용한 동적 데이터 전달

 상위 Component에서 하위 Component에 props 동적 데이터의 전달은 다음과 같습니다.

<!-- 상위 컴포넌트 -->
<app-header v-bind:하위 컴포넌트의 프롭스 속성 이름 = "상위 컴포넌트의 데이터 이름"></app-header>

<!-- ex -->
<app-header v-bind:itemList = "todoItemList"/>

<!-- 참고로 v-bind는 생략이 가능하다. -->
<app-header :itemList = "todoItemList"/>

 

3-3. Props 단방향 데이터 흐름

 props는 자식 속성과 부모 속성 사이에 하향식 단방향 바인딩으로 통신해야 합니다. 부모 속성이 업데이트가 되면 자식으로 전파가 되어 업데이트를 합니다. 하지만 그 반대의 경우(자식→부모)는 자식 컴포넌트가 실수로 부모의 상태를 변경하여 앱의 데이터 흐름을 이해하기 어렵게 만들 수 있기 때문에 자식 컴포넌트 내부에서 props를 변경하지 말아야 합니다. 

export default {
  props: {
    foo,
  },
  created() {
    // 자식 컴포넌트에서 props를 변경할 경우 콘손에 다음과 같이 경고 메시지가 나옵니다.
    // ❌ warning, props are readonly!
    //   (경고, props는 읽기 전용입니다!)
    this.foo = 'bar'
  }
}

 

 부모 Component에 영향을 주지 않고 props를 변경하고자 하는 경우에는 다음과 같은 두 가지 방법을 사용할 수 있습니다.

  • prop가 초기 값을 전달하기 위해 사용하고, 자식 컴포넌트는 props를 로컬 데이터 속성으로 사용하고자 하는 경우
export default {
  props: {
    initialCounter,
  
  data() {
    return {
      // props.initialCounter는 counter의 초기 값으로 사용됩니다.
      // 추후 props가 갱신되어도 counter 값이 업데이트 되지 않습니다.
      counter: this.initialCounter
    }
  }
}

 

  • prop가 변환이 필요한 경우 prop의 값을 사용하여 계산된 속성을 사용하고자 하는 경우
export default {
  props: {
    size,
  },
  computed: {
    // prop이 변경될 때, 계산된 속성은 자동으로 업데이트 됩니다.
    normalizedSize() {
      return this.size.trim().toLowerCase()
    }
  }
}

 

3-4. Prop 유효성 검사

 컴포넌트는 props에 타입과 유효성 관련 요구 사항을 지정할 수 있으며 지정한 요구 사항이 충족되지 않으면 Vue는 콘솔에서 경고 메시지가 출력됩니다.

  • required: true 가 지정되지 않은 모든 prop는 기본적으로 optional 입니다.
  • prop의 타입이 Boolean 이 아니고 선택사항인 경우, 누락되면 undefined 값을 가집니다.
  • prop의 타입이 Boolean 이고 누락된 경우, false 가 기본값이 됩니다.
  • prop가 누락되었거나 명시적으로 선언된 값이 undefined 이고 default 값이 정의되어 있다면 default 값이 사용됩니다.
props는 컴포넌트 인스턴스가 생성되기 이전에 유효성 검사를 실행하기 때문에 default 또는 validator 함수 내에서 인스턴스 속성(ex - data, computed 등)을 사용할 수 없습니다.
export default {
  props: {
    // 기본 타입 체크
    //  (`null`과 `undefined`는 모든 타입에서 허용됩니다)
    propA: Number,
    // 여러 타입 허용
    propB: [String, Number],
    // 문자열 필수
    propC: {
      type: String,
      required: true
    },
    // 기본 값을 가지는 숫자형
    propD: {
      type: Number,
      default: 100
    },
    // 기본 값을 가지는 객체
    propE: {
      type: Object,
      // 객체 또는 배열 기본값은 팩토리 함수에서 반환되어야 합니다.
      // 함수는 컴포넌트에서 받은 rawProps를 인자로 받습니다.
      // (rawProps: 부모 컴포넌트에게 받은 props 전체 객체)
      default(rawProps) {
        return { message: '안녕!' }
      }
    },
    // 사용자 정의 유효성 검사 함수
    propF: {
      validator(value) {
        // 값은 다음 문자열 중 하나와 일치해야 합니다.
        return ['성공', '경고', '위험'].includes(value)
      }
    },
    // 기본값이 있는 함수
    propG: {
      type: Function,
      // 기본값 객체나 배열을 정의하는 팩토리 함수가 아니라
      // 기본값으로 사용할 함수입니다.
      default() {
        return 'Default function'
      }
    }
  }
}

 

더보기
type
String
Number
Array
Object
Date
Function
Symbol

 

 

 

 

4. $emit

4-1. 이벤트 emit

 컴포넌트는 내장 메서드인 $emit 을 사용하여 템플릿 표현식(예: v-on 핸들러에서)에서 직접 사용자 정의 이벤트를 발신할 수 있다.

 

// 하위 컴포넌트
<template>
  <button v-on:click="passEvent">Click</button>
  <!-- 템플릿 표현식에서 직접 사용자 정의 이벤트를 발신할 수 있습니다. -->
  <!-- <button v-on:click="$emit('pass')">Click</button>
</template>

export default {
  data: function() {
    return {
      newTodoItem: ''
    }
  },
  methods: {
    passEvent: function() {
      this.$emit('pass');
    }}
  }
}
  • v-on:click="passEvent" - click 이벤트 발생 시 해당 컴포넌트의 passEvent 메서드 호출
  • this.$emit('pass') - 발생한 이벤트를 상위 컴포넌트에 전달

 

// 상위 컴포넌트
<template>
  <div id="app">
    <!-- <Emit v-on:하위 컴포넌트에서 발생한 이벤트명 = "상위 컴포넌트의 메서드명"></Emit> -->
    <!-- v-on은 @로 축약 가능 -->
    <Emit @pass="logText"></Emit>
  </div>
</template>

<script>
import Emit from './components/emit.vue'

export default {
  components: {
    Emit
  },
  methods: {
    logText() {
      console.log('logText 호출');
    }
  },
}
</script>
  • v-on:pass="logText" - 하위 컴포넌트에서 전달받은 이벤트로 해당 컴포넌트의 logText 메서드 호출

 

4-2. 이벤트 인자

 $emit 을 이용하여 이벤트와 함께 특정 값을 인자로 전달할 수 있습니다.

<!-- 자식 컴포넌트 -->
<button @click="$emit('increaseBy', 1)">
  Increase by 1
</button>

<!-- 부모 컴포넌트 -->
<my-button @increaseBy="(n) => count += n" />
<my-button @increaseBy="increaseCount" />
// 부모 컴포넌트
methods: {
  increaseCount(n) {
    this.count += n
  }
}

 

4-3. 이벤트 유효성 검사

 props 타입 유효성 검사와 유사하게 발신되는 이벤트는 배열 대신 객체 구문으로 정의된 경우 유효성을 검사할 수 있습니다. 유효성 검사를 추가하기 위해 이벤트에는 this.$emit 호출 시 전달되는 인자를 수신하고, 이벤트가 유효한지 여부를 나타내는 불리언 값을 반환하는 함수가 할당됩니다.

export default {
  emits: {
    // click 이벤트 유효성 검사 없음
    click: null,

    // submit 이벤트 유효성 검사
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('submit 이벤트 페이로드가 옳지 않음!')
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
}