본문 바로가기
Front-End (web)/Vue.js Typescript

[Vue.js/Typescript] 7. Props, Emit

by 햄과함께 2019. 8. 14.
320x100

이전까지는 Vue component 하나를 html, ts 파일 2개로 나누어서 관리했다.

컴포넌트 하나를 추가하려면 폴더 하나에 2개의 파일을 넣으려니 관리가 어렵다는 생각이 든다. (vue는 컴포넌트 단위 프레임워크인데 컴포넌트 하나 당 너무 많은 파일이 생성됨.)

그래서 이번부터는 vue 파일 하나(SFC)로 관리하기로 했다.

// src/vueShilms.d.ts 
declare module '*.vue' {
    import Vue from 'vue';
    export default Vue;
}

typescript 컴파일러가 vue파일을 인식할 수 있게 위 파일을 추가한다. 

참고 깃허브 - add vue SFC setting


컴포넌트들은 각자 데이터를 가지고 있다.

컴포넌트만의 데이터이기 때문에 다른 컴포넌트들이 무슨 데이터를 가지고 있는지 알 수 없다.

하지만 컴포넌트 간 데이터를 공유해야 하는 일은 무척 많다.

 

Parent 라는 컴포넌트에서 Child 라는 컴포넌트를 사용한다면, Parent 는 상위 컴포넌트(부모 컴포넌트)이고 Child는 하위 컴포넌트(자식 컴포넌트)라 한다.

이런 관계에서 데이터를 공유하는 방법은 Props, Emit이다.

 


Props

Props는 부모 컴포넌트의 데이터를 자식 컴포넌트로 전달할 때 사용한다. (Parent -> Child)

 

// src/components/Child.vue

<template>
  <div>
    Child : {{ name }}
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';

@Component({
  props: ['name'] // 부모에게서 공유 받을 데이터 명시
})
export default class Child extends Vue {}
</script>

일단 자식 컴포넌트(Child)를 만들어보면 위와 같다.

Child 컴포넌트를 호출하는 부모 컴포넌트에서 받아올 데이터는  name 이라고 명시해준다.

화면에는 받아온 데이터를 뿌려준다.

// src/components/Parent.vue

<template>
  <div>
    Parent 
    <child
      name="withham" // prop data(name) 전달
    />
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import Child from './Child.vue'; // import Child component

@Component({
  components: {Child} // use Child component
})
export default class Parent extends Vue {}
</script>

부모 컴포넌트(Parent)는 위와 같다. 

Child 컴포넌트를 임포트해서 컴포넌트로 사용하겠다고 명시해준다.

그리고 template에서 withham이라는 문자열을 child 컴포넌트로 넘겨준다.

Child 컴포넌트에서는 앞서 말했듯이 name이라는 Props를 받을 것이고 이를 화면에 출력해준다.

결과

실행해보면 위와 같이 Child 컴포넌트에서 Parent 컴포넌트에서 받은 withham 문자열을 출력해준다.


Emit

반대로 Child -> Parent 로 데이터를 전송할 때는 Emit Event를 사용한다.

// src/components/Parent.vue

<template>
  <div>
    Parent 
    data : {{ parentData }}
    <hr>
    <child
      name="withham"
      @emitEvent="emitEvent" // add emitEvent
    />
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import Child from './Child.vue';
@Component({
  components: {Child}
})
export default class Parent extends Vue {

  private parentData: string = 'default'; // change this data

  // add emit event
  private emitEvent(parentData: string) {
    this.parentData = parentData;
  }
}
</script>

Parent 컴포넌트를 위와 같이 수정해준다.

자식 컴포넌트에서 emit 이벤트를 발생시켜 변경될 데이터를 하나 정의해준다. (parentData)

자식 컴포넌트에서 호출할 emit 이벤트의 이름은 emitEvent라 네이밍했다.

emitEvent 함수는 파라미터로 문자열을 받고 이 값으로 데이터를 갱신한다.

 

// src/components/Child.vue

<template>
  <div>
    Child : {{ name }} <br>
    <br>
    parent data : <input
      v-model="parentData"
      placeholder="parent data"
    >
    <button @click="onEmitEvent"> // button click 할 때 emitEvent 호출
      부모에게 전송
    </button>
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';

@Component({
  props: ['name']
})
export default class Child extends Vue {

  private parentData: string = ''; // input box 바인딩 데이터
  private onEmitEvent(){
    // emitEvent를 호출하고 parentData를 파라미터로 넘겨준다.
    this.$emit('emitEvent', this.parentData); 
  }

}
</script>

Child 컴포넌트는 위와 같이 수정한다.

중요한 곳은 onEmitEvent 함수이다.

 this.$emit(<emit event 이름>[, 파라미터]) 로 emit 이벤트를 호출한다. 

위 코드에서는 input 박스를 하나만들어서 parentData라는 변수를 model로 바인딩 시켰다.

그리고 버튼을 클릭하면 parentData를 파라미터로 emitEvent라는 이름의 emit event를 호출한다. 

 

왼: 초기 / 오 : 버튼 클릭 시

결과 화면은 위와 같다. 

Parent data의 기본 값이 "default" 였기 때문에 초기엔 왼쪽과 같은 화면이다.

Child 컴포넌트의 input box에 "change"라는 문자열을 넣고 "부모에게 전송" 버튼을 클릭하면 "change" 문자열이 emitEvent 의 파라미터로 전송되어 parentData 값이 default에서 change로 변경된 것을 확인할 수 있다.


참고 깃허브 : add prop, emit example


 

참고 : [Vue.js Guide] Component

320x100

댓글