Vue3 - Composition API - Setup

📕 Argument

setup function은 두 가지 argument를 받는다.

  1. props
  2. context

📍 Props

setup 함수의 첫 번째 인자는 props이다. props는 반응형이다. 즉, 새로운 props가 들어오면, props는 반응하고, 업데이트된다.

props가 reactive하기 때문에, ES6의 destructing을 사용하면 안된다. destructing을 사용하면 props reactivity가 없어지기 때문이다.

props를 비구조화해야하는 경우가 생기면 toRefs 라는 함수를 이용해야 한다. 이 경우엔, 각각의 프로퍼티가 원래 객체의 프로퍼티의 ref이기 때문에 반응형이 유지된다.

toRefs

반응형 객체를 각 프로퍼티가 ref인 plain object로 변경시켜준다.

// MyBook.vue

import { toRefs } from 'vue'

setup(props) {
  const { title } = toRefs(props)

  console.log(title.value)
}

toRef

반응형 객체의 프로퍼티에 ref를 만들어낸다. toRef는 source property가 존재하지 않더라도, 사용가능한 ref를 반환한다. 따라서 optional props를 가져와야 할 때 유용하다. toRefs는 원본 객체에 존재하는 프로퍼티들에만 ref를 만들어내기 때문이다.

만약 title이 optional prop이라면, props에 title이 없을 수 있다.
이러한 경우에 toRefs는 title의 ref를 만들지 못한다. 대신, toRef를 써야 한다.
(복수나 단수냐의 차이로 이러는거 너무 헷갈리게 만든거 아닌가)

// MyBook.vue

import { toRef } from 'vue'

setup(props) {
  const title = toRef(props, 'title')

  console.log(title.value)
}

📍 Context

setup 함수의 두 번째 인자는 context이다.
context는 세 가지 프로퍼티가 있는 자바스크립트 객체이다.

  1. attrs
  2. slots
  3. emit

context 객체는 일반적인 자바스크립트 객체로, Reactive하지 않다. => 따라서 destructing으로 값을 가져와도 된다.

// MyBook.vue
export default {
  setup(props, { attrs, slots, emit }) {
    ...
  }
}

slotsattrs는 stateful object로, 컴포넌트가 업데이트되면, 항상 업데이트된다.
이 말은 곧 slots와 attrs에는 destructing을 사용하면 안되며 항상, attrs.x, slots.x처럼 프로퍼티를 가리켜야 한다. props와는 다르게, slots와 attrs는 Reactive하지 않다. 따라서, attrs와 slots의 변화에 따른 사이드이펙트를 주고 싶으면, onUpdated 라이프사이클 훅 안에서 사이드 이펙트를 줘야 한다.

📕 Component Property에 접근하기

setup이 실행될 때, 컴포넌트 인스턴스는 아직 생성되기 전이다.
따라서 다음과 같은 프로퍼티에만 접근할 수 있다.

  • props
  • attrs
  • slots
  • emit

즉, data, computed, methods와 같은 컴포넌트 옵션에는 접근할 수 없다는 의미이다. 참고로 인스턴스가 created되는 시점에는 data observation, computed, methods, watch/event callback이 설정되어있다.

📕 템플릿과 같이 사용하기

setup이 객체를 반환하면, 그 객체의 프로퍼티는 템플릿에서 접근할 수 있다.

setup에서 반환하는 refs는 템플릿에서 접근할 때에 automatically shallow unwrapped되어있다. 따라서, 템플릿에서 .value를 사용하지 않는다.

<!-- MyBook.vue -->
<template>
  <div>{{ collectionName }}: {{ readersNumber }} {{ book.title }}</div>
</template>

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

  export default {
    props: {
      collectionName: String
    },
    setup(props) {
      const readersNumber = ref(0)
      const book = reactive({ title: 'Vue 3 Guide' })

      // expose to template
      return {
        readersNumber,
        book
      }
    }
  }
</script>

📕 Render 함수와 같이 사용하기

setup can also return a render function which can directly make use of the reactive state declared in the same scope

setup이 렌더 함수를 반환할 수 있는데, 같은 스코프에 선언된 reactive state를 바로 사용할 수 있다.

// MyBook.vue

import { h, ref, reactive } from 'vue'

export default {
  setup() {
    const readersNumber = ref(0)
    const book = reactive({ title: 'Vue 3 Guide' })
    // Please note that we need to explicitly expose ref value here
    return () => h('div', [readersNumber.value, book.title])
  }
}

📕 this 사용하기

setup 안에서 this는 현재 active instance를 가리키고 있지 않다. setup()은 컴포넌트 옵션이 resolve되기 전에 호출되기 때문에, this는 다른 옵션에서의 this와는 다르게 동작하게 된다.

참고

Select a repo