owned this note
owned this note
Published
Linked with GitHub
---
tags: vue3
---
# 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로 변경시켜준다.
```javascript
// 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`를 써야 한다.**
(복수나 단수냐의 차이로 이러는거 너무 헷갈리게 만든거 아닌가...)
```javascript
// 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으로 값을 가져와도 된다.
```javascript
// MyBook.vue
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
```
**`slots`와 `attrs`는 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`를 사용하지 않는다.**
```javascript
<!-- 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를 바로 사용할 수 있다.
```javascript
// 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와는 다르게 동작하게 된다.
## 참고
- [Reactivity API - vue3](https://v3.vuejs.org/api/refs-api.html#torefs)