[TIL] Vue.js/defineEmits & defineExpose

JIEUN YANG·2022년 10월 2일
3

script setup 은 싱글 파일 컴포넌트(Single-File-Components) 구조에서 'Composition API' 를 사용하기 위한 진입점 역할을 하며, script 와 비교 했을 때 몇몇 장점이 존재한다.

  1. props와 emit이벤트를 타입스크립트로 선언이 가능하다.
  2. 런타임 퍼포먼스가 우수하다. ( script 문과 비교)
    -> 템플릿이 컴파일 될 때, 중간 프록시 객체 없기 때문)
  3. Visual Studio Code 등 통합 개발환경에서 언어 서버의 타입을 추론할 때 용이하다.

따라서 script setup의 문법 구조를 지켜야 하고, 그 중 헷갈렸던 두 개념을 정리해보려고 한다.



defineEmits

- 개념

emit 옵션을 사용하기 위해 선언하는 Vue 내장 APIs로, 하위 컴포넌트에서 상위 컴포넌트로 이벤트를 전달할 때 명시하고 사용한다.

- 예시

//button.vue 하위컴포넌트 

<template>
  	<button @click="$emit('test-emit')"> Emit 버튼 </button>
</template>


<script setup>
defineEmits(["test-emit"]);
</script>
//index.vue 상위컴포넌트 

<template>
  <button @test-emit="checkEmit"/>
</template>


<script setup>
import button from '@/component/button.vue'

const checkEmit = () => {
	console.log('emit 발생')
}
</script>



defineExpose

- 개념

script setup 구문을 사용하는 컴포넌트 인스턴스는 script setup 내에 선언한 어떠한 값도 컴포넌트 밖으로 내보낼 수가 없다. 그 이유는 script setup 구문 내에 갇히기 때문이고, 그렇게 갇힌 프로퍼티들은 ref$parent 체인을 통해 접근이 가능하다.

따라서, ref$parent 체인 내부의 속성값을 가져오려면 defineExpose APIs 로 내보내려는 속성들을 명시해야 하며, defineExpose 를 통해 내보낸 프로퍼티들은 ref 키워드로 상위 컴포넌트에서 하위 컴포넌트의 속성값에 접근이 가능하다.

- 예시

<template>
  <modal ref="refModal">
    <component :is="state.modal" :id="state.id" @close="closeModal" />
  </modal>
</template>

<script>
import modal from '@/component/modal'
import Regist from '@/component/regist'
import Modify from '@/component/modify'
export default {
  components: {
    Regist,
    Modify,
  },
}
</script>

<script setup>
import { ref, reactive } from 'vue'

const refModal = ref(null)

const state = reactive({
  modal: null,
})

const closeModal = () => {
  refModal.value.close()
}
</script>
  • modal 태그 안 엘리먼트는 modal.vue 컴포넌트의 slot 영역에 내장되어 렌더링된다.
  • ref 키워드를 통해 직접적으로 modal 컴포넌트의 속성값에 '접근' 할 수 있다.
  • 접근할 수 있는 프로퍼티들은 modal.vue 컴포넌트에서 defineExpose 내부에 명시한 속성들이다.
  • refMoal.value 에는 open() close() 함수가 존재한다.

//modal.vue 하위컴포넌트

<template>
   <div v-if="state.visible">
       <slot></slot>
   </div>
</template>

<script setup>
import { reactive } from 'vue'


const state = reactive({
  visible: false,
})

// 부모 컴포넌트에서 접근하기 위한 함수.
const open = () => {
  state.visible = true
}
const close = () => {
  state.visible = false
}

defineExpose({
  close,
  open,
})
</script>
  • defineExpose APIs 를 통해 close(), open() 함수를 명시하였고, ref 속성으로 접근 시 해당 함수들을 지니고 있다.
  • ref 로 접근한 컴포넌트의 프로퍼티의 제어는 불가능하며, 속성값들의 read 만 가능하다.

    프로퍼티 선언과 값을 할당한 이후에 defineExpose({}) 해줘야 한다. js의 코드 컴파일러는 top->down 형식으로 코드를 읽기 때문에 선언문 이전에 defineExpose를 하면 ref 로 프로퍼티를 호출할 때 undefined 에러를 만날 것이다.




참고

vue공식문서

profile
violet's development note

0개의 댓글