Today I Learned 49 - Vue / Pass Props & Emit Events

angie·2022년 11월 4일

Vue.js

목록 보기
7/12
post-thumbnail

완전히 동일한 data를 서로 다른 component에서 주고 받기 위한 방법이다. '부모 컴포넌트-자식 컴포넌트'의 관계에서 data를 보내는 방향에 따라 방법이 달라진다.

  • 부모 컴포넌트에서 자식 컴포넌트로 보낼 때 : pass props
  • 자식 컴포넌트에서 부모 컴포넌트로 보낼 때 : emit event

1. pass props

  • 부모 컴포넌트에서 자식 컴포넌트로 데이터를 보낼 때 사용하는 방법
  • 자식 컴포넌트에서 script 부분에 props 옵션에 명시적으로 선언해야한다.

1) Prop Casing (이름 규칙)

HTML의 속성 이름은 대소문자를 구분하지 않기 때문에, DOM 내 템플릿을 사용할 때 자바스크립트에서 camelCase로 작성된 prop의 이름은 html에서는 cebab-case로 사용해야한다.

정리!

  • html에서는 kebab-case 사용
  • js에서는 camelCase 사용

2) Passing Static Props (정적 데이터 보내기)

  • 부모 컴포넌트의 template에서 자식 컴포넌트를 사용할 때 태그의 속성에 데이터를 전달
  • 부모 컴포넌트에서 데이터를 전달할 때는 HTML attribute로 작성하므로 kebab-case 사용
  • 자식 컴포넌트에서 사용할 때는 JavaScript를 담당하는 script 부분에 작성하므로 camelCase 사용
// MyParent.vue
<template>
  <div>
  	// kebab-case
  	<MyChild static-props="component에서 child로"/>
  </div>
</template>
// MyChild.vue
<template>
  <div>
  	// camelCase
  	<p>{{ staticProps }}</p>
  </div>
</template>

<script>
export default {
	name: 'MyChild',
    props: {
      	// camelCase
    	staticProps: String,
    }
}
</script>

3) Passing Dynamic Props

  • 부모 컴포넌트의 data의 변수에 담은 데이터를 보냄
  • v-bind를 사용하여 자식 컴포넌트에 동적 데이터를 전달
  • 부모 컴포넌트에서 해당 데이터가 업데이트되면 자식 컴포넌트의 데이터도 업데이트

예시

// MyParent.vue
<template>
  <div>
  	// kebab-case = "camelCase"
  	<MyChild v-bind:dynamic-props="dynamicProps"/>
  </div>
</template>

<script>
export default {
	name: 'MyParent',
    data: function() {
    	return {
          	// camelCase
        	dynamicProps : "This is data"
        }
    }
}
</script>
// MyChild.vue
<template>
  <div>
  	// script에 등록한 이름
  	<p>{{ dynamicProps }}<p/>
  </div>
</template>

<script>
export default {
	name: 'MyChild',
    props: {
    	dynamicProps: String,
    }
}
</script>

4) Pass Props

보낼 때 속성 이름, 데이터 받을 때 이름 등 헷갈리는 부분을 정리!

예시

// MyParent.vue
<template>
  <div>
  	// MyChild에서 my-props란 이름으로 데이터를 받는다.
  	// 연결된 MyParent의 데이터의 이름은 dynamicProps이다.
  	<MyChild v-bind:my-props="dynamicProps"/>
  </div>
</template>

<script>
export default {
	name: 'MyParent',
    data: function() {
    	return {
          	// camelCase
        	dynamicProps : "This is data"
        }
    }
}
</script>
// MyChild.vue
<template>
  <div>
  	// MyParent에서 받은 데이터
  	<p>{{ myProps }}<p/>
  </div>
</template>

<script>
export default {
	name: 'MyChild',
    props: {
      	// MyParent에서 my-props를 camelCase로 받아온다.
    	myProps: String,
    }
}
</script>

주의!

  • v-bind 로 묶여있는 " " 안의 구문은 자바스크립트 구문
// num-props = String
<SomeComponent num-props="1"/>
  
// num-props = Number
<SomeComponent :num-props="1"/>
  • 첫번째 num-props는 static, 두번째는 dynamic이다.
  • 두번째의 경우 자바스크립트 구문이기 때문에 Number 타입의 변수이다.

2. Emit Event

  • 자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달할 때는 이벤트를 발생시킴
  1. 데이터를 이벤트 리스너의 콜백함수의 인자로 전달
  2. 상위 컴포넌트는 해당 이벤트를 감지하여 데이터를 받음

1) $emit

  • $emit('event-name') 형식으로 부모 컴포넌트의 event-name이라는 이벤트가 발생했다는 걸 알림
  • $emit('event-name', data)의 형식으로 두번째 인자로 데이터를 전달 가능
  • 두 번째 인자로 담아 전달 시 해당 이벤트와 연결된 부모 컴포넌트의 함수의 인자로 사용 가능

예시1

<!-- 자식 컴포넌트 -->
<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>
<!-- 부모 컴포넌트 -->
<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

부모 컴포넌트에서 이벤트를 수신할 때 $event를 사용하여 자식 컴포넌트에서 보낸 데이터을 사용할 수 있다. (위 예시의 경우, 0.1)

예시2

위 예시에서 부모 컴포넌트에서 $event가 아니라 메소드를 사용하여 데이터를 사용하는 경우의 예시이다.

<!-- 자식 컴포넌트 -->
<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>
<!-- 부모 컴포넌트 -->
<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>
// 부모 컴포넌트의 script 내에 작성
methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

해당 메소드의 첫 번째 매개변수로 전달된다.

2) emit with dynamic data (v-model 사용)

// MyChild.vue
<template>
  <div>
  	<input
		type="text"
		v-model="childInputData"
		@keyup.enter="childInput"
	/>
  </div>
</template>

<script>
export default {
	...
	data: function() {
    	return {
        	childInputData: null,
        }
    },
    methods: {
    	childInput: function() {
          	// 'event-name', data
        	this.$emit('child-input', this.childInputData)
        }
    }
}
</script>
// MyChild.vue
<template>
  <div>
  	<MyChild @child-input="getChildData"/>
  </div>
</template>

<script>
export default {
	...
    methods: {
      	// // MyChild로부터 받은 childInputData를 inputData라는 이름으로 받았다.
    	getChildData: function(inputData) {
          	console.log(inputData)
        }
    }
}
</script>
profile
better than more

0개의 댓글