FrontEnd/Vue

[Vue3] Setup hook

Grace 2023. 4. 2. 23:20

Setup

setup() 함수(hook)는 Composition API 사용을 위한 진입점 역할을 합니다. 그리고 setup 함수는 컴포넌트 인스턴스가 생성되기 전에 실행됩니다.

기본 사용

반응형 API(Reactivity API)를 사용하여 반응형 상태를 선언하고 script setup에서 객체를 반환하여 <template>에 노출할 수 있습니다. setup() 함수를 사용할 수 있지만 SFC와 Composition API를 함께 사용하는 경우 script setup을 사용하는 것을 권장하고 있기에, script setup 사용 기준으로 설명하겠습니다.
반환된 객체의 속성은 구성 요소 인스턴스에서도 사용할 수 있습니다(다른 옵션이 사용되는 경우):

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

const count = ref(0)

onMounted(()=> console.log(count)) // 0
</script>

<template>
  <button @click="count++">{{ count }}</button>
</template>

Props 접근

setup 함수의 첫 번째 매개변수는 props 입니다. props는 반응형 객체입니다.

<template>
  <!-- 템플릿 내에서 사용할 때는 props를 호출하지 않아도 됩니다. -->
  <div class="nickname">{{ nickname }}</div>
</template>

<!-- By JavaScript -->
<script setup>
import { defineProps } from 'vue'; // 생략 가능

const props = defineProps({
  nickname: string,
})

console.log(props.nickname); // props를 먼저 선언해야 nickname을 확인 할 수 있습니다.
</script>

<!-- By TypeScript -->
<script setup lang="ts">
import { defineProps } from 'vue' // 생략 가능

interface Props {
  nickname: string;
}

const props = defineProps<Props>()

console.log(props.nickname) // props 에서 접근할 것!
</script>

주의 할 것은 props에서 전달되는 아이템은 객체 구조분해 할당이 되지 않고, 만약 가능하다 하더라도 반응성을 잃을 수 있으므로 props.xxx 형식으로 props에 액세스하는 것이 좋습니다.

toRef, toRefs

만약 props의 반응성을 유지하면서 구조 분해 할당을 해야 한다면(예: 외부 함수에 prop을 전달해야 하는 경우) toRefs() 및 toRef() 유틸리티 API를 사용하여 이를 수행할 수 있습니다.

<script setup lang="ts">
  import { defineProps, toRefs, toRef } from 'vue'
  
  interface Props {
    nickname: string;
  }
  
  const props = defineProps<Props>()
  
  const { nickname } = toRefs(props) // props 구조 분해
  const nickname = toRef(props, 'nickname') // nickname 단일 변수만 필요한 경우
</script>

Setup Context

기존에는 setup 함수에 Setup Context 객체가 두번째 변수로 전달되었습니다. 컨텍스트 객체는 반응형이 아니고 setup 함수 내에서 유용하게 사용할 수 있는 속성을 갖고 있습니다.

  • slots: 부모 컴포넌트에서 자식 컴포넌트의 엘리먼트를 지정할 때 사용합니다.
  • attrs: 컴포넌트에 전달되는 속성 중 props, emits에서 명시적으로 선언되지 않은 속성입니다(style, id, class 등). 폴스루 속성이라고 부릅니다.
  • emit: 자식 컴포넌트에서 부모컴포넌트로 데이터를 전달할 때 사용합니다.
  • expose: template refs(템플릿 참조)를 통해 상위 컴포넌트에서 컴포넌트의 인스턴스에 접근할 때 노출되는 속성을 명시적으로 제한하는 데 사용할 수 있는 함수입니다.

attrs과 slots의 경우 템플릿에서 $slots와 $attrs로 직접 접근이 가능하기 때문에 script setup 내부에서 사용하는 경우는 많이 없습니다. 다만, 꼭 필요한 경우에는 useSlotsuseAttrs를 사용할 수 있습니다.

<script setup>
import { useSlots, useAttrs } from 'vue'

const slots = useSlots();
const attrs = useAttrs();
</script>
<script setup>
import { defineEmits } from 'vue'; // 생략 가능

const emits = defineEmits(['change', 'delete'])
</script>
<script setup>
import { defineExpose, ref } from 'vue' // defineExpose는 생략 가능

const publicCount = ref(0)
const privateCount = ref(0)

defineExpose({ count: publicCount })
</script>