vue2의 템플릿은 하나의 루트 엘리먼트만 허용했지만 vue3 부터는 여러 개가 가능합니다. 그러므로 불필요한 wrapper div를 제거 할 수 있습니다.
<template>
<div>
<div class="test-label">
{{test}}
</div>
<input type="text"/>
</div>
</template>
이 경우 vue2에서 template 바로 아래 div는 아무 기능없이 루트 엘리먼트를 하나로 유지하기 위해 쓰이는 것인데, vue3에선 필수가 아닙니다.
하지만, 여러개의 루트 엘리먼트를 권장하지는 않습니다. BEM 규칙하에 원활한 스타일링을 위해 컴포넌트를 래핑하는 스타일 엘리먼트를 배치하는 것을 권장합니다.
또한, 템플리에서 변수를 호출하는 방식도 변경되었는데, 기존에는 props는 method 등을 구분없이 이름만으로 호출하도록 동작했지만 이제는 문맥상으로 분리할 수 있게 되었습니다.
ex)
<template>
<div>
<div class="test-label">
<!--{{test}}-->
{{state.test}}
</div>
<input type="text"/>
</div>
</template>
vue3에서 가장 큰 특징으로 기존의 data, method 등의 선언이 모두 setup 이라는 메소드 안으로 편입되었습니다.
기존vue2 ->
// Vue2.x
export default {
props: {
title: String
},
data () {
return {
test: '',
sample: ''
}
},
methods: {
sendTest () {
// sendTest method
}
}
}
vue3 ->
// Vue 3.x
export default {
props: {
title: String
},
setup () {
const state = reactive({
test: '',
sample: ''
})
const sendTest = () => {
// sendTest method
}
return {
sendTest,
state
}
}
}
vue3에서는 props와 setup이 같은 계층에 존재하고 data는 state, method는 각각의 기명함수로 작성되어 한번에 반환되도록 변화하였습니다.
state도 단순 선언이 아닌 vue reactive를 사용합니다. Reactive는 vue가 반응형 시스템을 유지하기 위해서 사용하는 간단한 JS 객체입니다.
Reactive는 그림과 같이 작동합니다.
vue2는 data, method와 같은 hierachy에서 선언하였지만 vue3에서는 setup내부에서 선언 하도록 하였습니다.
vue3 ->
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured } from 'vue'
export default {
setup() {
onBeforeMount(() => {
// ...
})
onMounted(() => {
// ...
})
onBeforeUpdate(() => {
// ...
})
onUpdated(() => {
// ...
})
onBeforeUnmount(() => {
// ...
})
onUnmounted(() => {
// ...
})
onActivated(() => {
// ...
})
onDeactivated(() => {
// ...
})
onErrorCaptured(() => {
// ...
})
}
}
state 선언문 내에 computed 속성에 대한 선언 구문을 추가하는 것으로 변화하였습니다.
vue2 ->
export default {
// ..
computed: {
getChangeTest () {
return this.test.change()
}
}
}
vue3 ->
import { reactive, computed } from 'vue'
export default {
props: {
title: String
},
setup () {
const state = reactive({
test: '',
sample: '',
getChangeTest: computed(() => state.test.change())
})
// ...
}
이 API는 컴포넌트를 선언하고 조립하기 위한 새로운 API로 전반적으로 논리적이고 가독성이 좋은 코드를 작성하기 위해 도입되었습니다.
기존에는 볼륨이 큰 컴포넌트는 상태 변수 선언, computed 메소드 바인딩, methods, lifecycle hook 선언 등이 혼재되어 논리에서 어긋난 구조를 생성하고 있어, 가독성을 향상하고 논리를 보존하는 방향으로 개선한 것이 Composition API입니다.
기존에 props 뿐 아니라 method, data등을 this에 바인딩함으로써 코드의 가독성이 떨어지는 것을 개선하기 위한 변화입니다.
vue2 ->
mounted () {
console.log('title: ' + this.title)
}
기존 vue2 코드는 title이 props의 값인지 data인지 method인지 구별하기 힘듭니다.
vue3 ->
setup (props) {
// ...
onMounted(() => {
console.log('title: ' + props.title)
})
// ...
}
vue3에서는 setup은 props를 사용하기 위해 attribute로 받아야하고 다음과 같이 사용해 구분하기 쉬워집니다.
emit도 props와 비슷하게 작동합니다.
vue2 ->
testSample () {
this.$emit('testSample', {
test: this.test,
sample: this.sample
})
}
vue3 ->
setup (props, { emit }) {
// ...
const testSample = () => {
emit('testSample', {
test: state.test,
sample: state.sample
})
}
// ...
}
Suspended Component는 기존에 React에서 지원하던 컴포넌트 중 하나로 컴포넌트 내에 있는 async 구문이 완료 되지않으면 fallback template를 대신 표시하도록 할 수 있습니다.
ex)
<Suspense>
<template #default>
<UserProfile />
<FunnyCats />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
#default 와 #fallback으로 구분하며 여러 개의 async component가 존재하는 경우 모든 async가 종료되면 fallback이 해제됩니다.
참고사이트
Vue3 변경점 정리