data(){}
, methods:{}
에 맞춰 무조껀 나눠야했다는 것이다.앞서 말한 Options API의 1단점을 극복하고자 setup() 메서드를 사용해서 로직을 번들로 만들어 컴포넌트 구성 객체에 추가하는 것이다.
위치는 data(){}
, methods:{}
와 동일한 위치에 선언해주면된다.
이 setup(){}
은 data(){}
, methods:{}
, computed:{}
,watch:{}
을 대체(통합)한다.
components:{}
, props:[]
는 바뀌지 않는다.템플릿 코드나 v-if, 데이터 바인딩 같은 기능은 배운 내용 그대로이다.
<template>
{{userName}}
</template>
...
setup(){
const urName = ref('정우');
return {userName:urName};
}
...
여기서 나온 ref는 앞전에 input에 사용하던 ref와는 다르다.
setup()에서 호출할 수 있는 함수라는 점에서 다르다. ref는 소위 참조를 생성하는데 DOM 요소에 대해서 참조하는 것이 아니라 값을 참조해서 템플릿에서 쓸 수 있게 해준다. 이렇게 하면 반응형 문자열이 생성된다.
ref는 아무런 값이나 생성하는 것이 아니라 반응형 값을 생성하기 때문에 이 값을 바꾸면 Vue도 인식하고 감시할 수 있어서 값이 바뀌거나 템플릿에 사용되면 Vue는 DOM에서 템플릿을 업데이트할 수 있다.
여기서는 this. 키워드는 사용하지 않는다. setup() 메서드에서 this. 키워드를 사용할 수는 있지만 methods에서 사용했을 때처럼 Vue 구성 객체를 참조하지 않는다.
this.
키워드로 대상에 액세스할 수 없는 것이다.props:[]
에도 접근할 수 없을 것이다.작동방식 : 내부적으로는 객체를 생성하고 문자열은 그 객체에 저장이 되고 Vue는 이 객체를 감시해서 기존 문자열이 아닌 새로운 값을 배치하면 변화를 인식하고 DOM을 업데이트한다.
앞서 ref를 사용하는 이유는 reactive한 값을 가질 수 있기 때문이라고했는데 값을 한번 바꿔보자
...
setup(){
const urName = ref('정우');
setTimeout(function (){
urName = "개발자"
},2000);
return {userName:urName};
}
...
이렇게 하면 오류가 난다. 왜? 우선 변수를 const로 선언함 2번 const가 아닌 let으로 한다고 해도 이 경우에는 문자열이 기존 ref를 덮어쓰므로 기존 ref를 잃게 되는데 Vue에 값이 변화하면 알려주는 ref의 내장 메커니즘이 필요하기 때문에 ref가 없어지면 안 되기 때문이다.
그렇다면 어떻게 바꿔주면 좋을까?
...
setup(){
const urName = ref('헬창');
setTimeout(function (){
urName.value = "개발자"
},2000);
return {userName:urName};
}
...
setup 메서드는 한 번만 실행되는데 이때 템플릿에 새 값과 객체를 반환하지 못한 것이다.
그렇기 때문에 ref가 필요한 거고 따라서 uName에 이런 식으로 새로운 값을 지정할 일이 없으므로 상수를 사용하는 것이다.
ref 함수가 객체를 생성한다고 언급하였는데 내부적으로 객체에는 .value 프로퍼티가 포함된다. ref 함수에 전달하는 값은 value 프로퍼티에 저장되고 uName 객체에서 .value 프로퍼티에 새로운 값을 지정할 수도 있다.
<template>
<section class="container">
<h2>{{ userName }}</h2>
</section>
</template>
setup()
메서드의 반환 객체에서 ref
를 활용한 경우 Vue가 자동으로 .value 프로퍼티의 값을 가져가므로 <h2>에서는 .value에 액세스하지 않는다.
userName은 ref를 가리키고 있고 새로운 값을 설정하려면 .value 프로퍼티를 사용해야 한다. 그러나 ref를 템플릿에 전달하면 Vue는 자동으로 .value 프로퍼티를 확인한다. 따라서 템플릿에서는 .value를 쓸 필요가 없이 ref만 사용하면 Vue가 나머지를 처리하는 구조이다.
...
setup(){
const user = ref({
name: '헬창',
age: 27
});
setTimeout(function (){
user.value.name = "개발자"
},2000);
return {userName:user.vlaue.name, userAge:user.value.age};
}
console.log(user);
...
이렇게 넣으면 과연 reactive하게 작동할까? => NO!
만일 ref의 값으로 객체를 전달하면 Vue가 객체 내부의 변화도 파악할 수 있도록 그 객체는 Proxy로 래핑된다.\
문제는 템플릿에 정보를 전달하는 방식에 있다. return 문에서도 객체 내부의 정보를 액세스한다. user.value를 사용해서 ref에 저장된 객체에 액세스하여 이름과 나이 프로퍼티에 접근할 수 있는데 바로 여기에서 문제가 발생한 것이다.
Vue는 문자열과 숫자가 활용된다는 것만 알 수 있는데 이렇게 구체적인 값의 정보는 지속해서 파악하지 못하기 때문에 변화를 감지하지 못 하는 것이다.
<template>
<section class="container">
<h2>{{ user.name }}</h2>
<h2>{{ user.age }}</h2>
</section>
</template>
<script>
setup(){
const user = ref({
name: '헬창',
age: 27
});
setTimeout(function (){
user.value.name = "개발자"
},2000);
return {user: user};
}
</script>
<script setup>
import {reactive, ref} from 'vue';
const user = reactive({name:'alex',age:27})
const refUser = ref({name:'alice', age: 22})
setTimeout(function (){
user.name = '응가'
refUser.value.age = 26
},2000);
</script>
reactive는 ref와 비슷하지만 객체용으로 만들어졌다는 점에서 다르다.
사용자 상수에서 ref 대신에 reactive를 호출하고 기존 객체를 reactive에 전달한다.
ref는 문자열, 숫자, 객체 등 다양한 값을 사용했다면 reactive는 객체만을 이용한다.
reactive는 중요한 작업을 하나 하는데 이름과 나이를 value 프로퍼티를 갖는 객체로 래핑하고 기존 값에 포인터를 가리키는 게 아니라 reactive에 전달한 객체를 프록시로 래핑해서 반응형으로 만들어서 객체를 사용할 수 있게 해준다. 마치 래퍼가 없는 것처럼 사용할 수 있는 것이다.
전에는 ref 객체로 value 프로퍼티와 게터와 세터를 값으로 가졌다면 이제는 프록시 객체가 객체를 래핑하고 내부 리스너로 프로퍼티의 변화를 감시한다.