# Vue 3.0
์๋ก ๋ฑ์ฅํ Vue.js Composition API(๋ทฐ 3.0)์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
# ๊ธฐ์กด์ ๋ฌธ์ ์
- ๋ณต์กํ ์ฑ์์ ์ฝ๋ ์ฌ์ฌ์ฉ ๋ฐฉ๋ฒ์ ํ๊ณ
- HOC
- ๋ฏน์ค์ธ
# ๊ฐ๊ณ ์ ํ๋ ๋ฐฉํฅ
- ์ธ์คํด์ค ์ต์ ๋จ์๊ฐ ์๋๋ผ ํน์ ๊ธฐ๋ฅ์ด๋ ๋ ผ๋ฆฌ์ ๋จ์๋ก ์ฝ๋๋ฅผ ๊ทธ๋ฃนํ ํ๋ ๊ฒ. ๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ทธ๋ฃนํ๋ ๋ก์ง์ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ์ฌ์ฌ์ฉํ๊ธฐ
most of us opt to organize files by feature or responsibility
- ss
# composition API์ ์ฅ์
ref
,reactive
API๋ก ์์ฑํ reactive ๋ฐ์ดํฐ๋ค์ ํ ํ๋ฆฟ์๋ง ๊ผญ ์ฐ์ง ์์๋ ๋๋ ์ฅ์ ์ด ์๊ธด๋ค. ์ปดํฌ๋ํธ์ ๋ณ๊ฐ๋ก ์ฌ์ฉํ ์ ์๋ ๋ฐ์์ฑ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ ์ ์์.- ์ปดํฌ๋ํธ ์ต์
์์ฑ์ด ์กด์ฌํ๊ธฐ ์ ์
setup
API๊ฐ ์คํ๋๋ฏ๋กthis
๋ก ์ปดํฌ๋ํธ๋ฅผ ์ ๊ทผํ ์ ์๋ค. ๋์context
์ฌ์ฉ. (๋ง์น ๊ธฐ์กด์ functional component๋ฅผ ๋ณํํด์ ์ฌ์ฉํ๋ ๋๋) setup
API์ ๋ ๋ฒ์งธ ์ธ์์ ์ ๊ณต๋๋ ์ต์ ๋ค
setup(props, context) {
context.attrs
context.slots
context.parent
context.root
context.emit
}
# composition API์ ๋ํ ์๊ฐ
- API ํจ์๋ก ๋ถ๋ฌ์จ ๋ฐ์ดํฐ๋ฅผ ์ปดํฌ๋ํธ
data
์ ์ฐ๊ฒฐํ๊ธฐ ์ ์ ๊ฐ๊ณตํ ์ผ์ด ๋ง์๋ฐ ์ด๋ฅผ ์ปดํฌ์ง์ API ํจ์ ๋ ์ด์ด์ ๋ฃ์ผ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ฆ. ์ด๋ฅผ ์๋น์ค ๋ ์ด์ด๋ผ๊ณ ์น๋ฉด ๊ธฐ์กด์๋ ์คํ ์ด๋ผ๋ ๊ฐ ๋ฏน์ค์ธ์ ๋ถ์ฐ์ํค๊ฑฐ๋ ์ต๊ทค๋ฌ์ฒ๋ผ ์๋น์ค ํ์ผ์ ๋ง๋๋ ๊ฒฝํฅ์ด ์๋ ๋ฏ.
# Note Taking
ref
๊ฐ ๊ฐ์ฒด์ธ ์ด์ ๋number
,string
๋ฑ์ ์์ ํ์ ์ด passed by value ์ด๊ธฐ ๋๋ฌธ์computed
๋ด๋ถ ๋ก์ง ํ๋ฆ์ passed by reference์ธobject
๋ชจ์์ด ํ์ํ์
// won't work
function computed(getter) {
let value
watchEffect(() => {
value = getter()
})
return value
}
// works like a charm
function computed(getter) {
let ref = {
value: null
}
watchEffect(() => {
ref.value = getter()
})
return ref
}
# ref
๊ธฐ์กด ๋ทฐ ๋ฒ์ ์์๋ ref
๊ฐ ๋ทฐ ํ
ํ๋ฆฟ์ DOM ๋๋ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๋ฆฌํค๋ ์์ฑ์ผ๋ก ์ฌ์ฉ๋์์ต๋๋ค.
Vue 3์์๋ ref
๊ฐ reactive reference
๋ฅผ ์๋ฏธํฉ๋๋ค.
Vue 3์ ref
๋ ๋ฆฌ์กํฐ๋ธํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ฆฌํฌ ๋ฟ๋ง ์๋๋ผ ํ
ํ๋ฆฟ ํํ์๋ ํจ๊ป ๊ฐ๋ฆฌํต๋๋ค.
TIP
TLDR
ref
meansreactive reference
reactive
์์ ref
๊ฐ์ ์ฌ์ฉํ๋ฉด .value
๋ก ์ ๊ทผํ ํ์๊ฐ ์๋ค.
// ref
import { ref, watch } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
// reactive
const state = reactive({
count: 0,
double: computed(() => state.count * 2)
})
// no need to use `state.double.value`
console.log(state.double)
# reactive์ ref์ ์ฐจ์ด์ ?
reactive
๋ ๊ธฐ์กด ๋ทฐ ๋ฌธ๋ฒ์ data
์์ฑ ๋๋์ด๊ณ , ref
๋ ์ข ๋ ๋ฆฌ์กํฐ๋ธ ์์ฑ์ ๊ฐ๋ณ์ ์ผ๋ก ์ ์ธํ๋ ๋๋.
// reactive
const event = reactive({
count: 3,
doubled: computed(() => event.count * 2)
})
// ref
const count = ref(3)
const doubled = computed(() => count.value * 2)
- ๋๊ฐ ๋ค ์ด์ฐจํผ
event.count
๋ก ์ ๊ทผํ๋count.value
๋ก ์ ๊ทผํ๋ ์์ฑ์ผ๋ก ํ๋จ๊ณ ๋ ๋ค์ด๊ฐ์ ์ ๊ทผํด์ผ ํ๋๊ฑด ๊ฐ๋ค.
# reactive๊ฐ ๋ ์ ์ธํ๊ธฐ ํธํ ๊ฒ ๊ฐ์๋ฐ์?
์ ์ธํ๋ ์ชฝ ์ฝ๋๋ง ๋ณด๋ฉด ๊ทธ๋ ์ง๋ง ์ค์ ๋ก๋ ํ
ํ๋ฆฟ์์ ์๋์ ๊ฐ์ ๋ถํธํจ์ด ๋ฐ์ํ๋ค.
reactive
์ ์ผ์ด์ค๋ฅผ ๋ณด์.
<!-- reactive -->
<div>count: {{ event.count }}</div>
<div>doubled: {{ event.doubled }}</div>
// reactive
const event = reactive({
count: 3,
doubled: computed(() => state.count * 2)
})
์์ธ๋ก ref
์์ฑ์ด ์ ์ธํ ๋ ์กฐ๊ธ ๋ถํธํ์ง๋ง ํ
ํ๋ฆฟ์์๋ ์ ๊ทผํ๊ธฐ๊ฐ ํธํ๋ค.
<!-- ref -->
<div>count: {{ count }}</div>
<div>doubled: {{ doubled }}</div>
// ref
const count = ref(3)
const doubled = computed(() => count.value * 2)
# ๊ทธ๋๋ reactive๊ฐ ์ข ๋ ํธํ ๊ฒ ๊ฐ์๋ฐ ์ด๋ป๊ฒ ๋ฐฉ๋ฒ์ด ์์๊น์?
ES6์ ๋์คํธ๋ญ์ฒ๋ง ๋ฌธ๋ฒ์ ์๊ฐํด๋ณด๋ฉด ์ ์ง ์๋์ ๊ฐ์ ์๋๊ฐ ๊ฐ๋ฅํ ๊ฒ ๊ฐ๋ค.
<!-- reactive -->
<div>count: {{ event.count }}</div>
<div>doubled: {{ event.doubled }}</div>
// reactive
function setup() {
const event = reactive({
count: 3,
doubled: computed(() => state.count * 2)
})
// ์ ์ ๋ฌธ๋ฒ
return { event }
}
๊ธฐ๋ณธ์ ์ผ๋ก setup
API์์ ๋ฐ์์ฑ์ด ์ฃผ์
๋ ๊ฐ(reactive ๋๋ ref)์ ๋ฐํํด์ค์ผ ํ๋๋ฐ ์ด ๋ ๋ญ๊ฐ ์๋์ ๊ฐ์ด ํด๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค.
<!-- reactive -->
<div>count: {{ count }}</div>
<div>doubled: {{ doubled }}</div>
// reactive
function setup() {
// ...
return { ...event } // X
}
// reactive
function setup() {
// ...
return { event.count, event. doubled } // X
}
์์ ๊ฐ์ ํํ๋ก๋ reactive
์์ ์ ์ธ๋ ์์ฑ๋ค์ ๋ฐ๋ก ํ
ํ๋ฆฟ์์ ์ ๊ทผํ ์๊ฐ ์๋ค.
์ด ๋ ์ฌ์ฉํ ์ ์๋๊ฒ toRef
API๋ค
<!-- reactive -->
<div>count: {{ count }}</div>
<div>doubled: {{ doubled }}</div>
import { toRefs } from 'vue';
// reactive
function setup() {
// ...
return { ...toRefs(event) } // O
return toRefs(event); // O
}
# ๋ผ์ดํ ์ฌ์ดํด ํ
setup
API์์ ๊ธฐ์กด ๋ผ์ดํ ์ฌ์ดํด ๊ฐ๋
๊ณผ ํ
์ ๋๋ถ๋ถ ์ ์ง๊ฐ ๋์๊ณ ์๋ 4๊ฐ์ง์ ๋ณํ๋ง ์๋ค.
beforeCreate
,created
๋setup
ํจ์ ์์์์ ๋ก์ง ์คํ์ผ๋ก ๋์ผํ ํจ๊ณผ๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ ๊ฑฐ๋จbeforeDestroy
,destroyed
๋ ๋ ๋ช ์์ ์ธ ์ด๋ฆ์ผ๋ก ๋ณ๊ฒฝ ->beforeUnmount
,unmounted
onRenderTracked
: ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆฌ๊ธฐ ์ํ ๋ฆฌ์กํฐ๋ธ ๋ํ๋์(๋ฐ์์ฑ์ด ์ฃผ์ ๋ ๋ฐ์ดํฐ ๋ณํ ์ ๋๋ก ์ดํด)๊ฐ ์ฒ์์ผ๋ก ๊ฐ์ง๋์์ ๋. ๋๋ฒ๊น ์ฉ๋onRenderTriggered
: ์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ด ์ผ์ด๋ฌ์ ๋. ์ด๋ค ์ด์ ๋ก ํ๋ฉด์ด ๋ค์ ๊ทธ๋ ค์ง๊ฑด์ง ๋๋ฒ๊น ํ๊ธฐ ์ํ ์ฉ๋.
๋ฌธ๋ฒ์ ์๋์ ๊ฐ์ด ๋ณ๊ฒฝ๋์๋ค.
// ๊ธฐ์กด
new Vue({
created() {
},
beforeMount() {
}
})
// setup
setup() {
onBeforeMount(() => {
console.log("Before Mount!");
});
onMounted(() => {
console.log("Mounted!");
});
}
# ๋ผ์ดํ ์ฌ์ดํด ํ
- ๊ธฐ์กด์ ๋ผ์ดํ ์ฌ์ดํด ํ
์ ์์
on
์ ๋์ฌ๊ฐ ๋ถ๋๋ค.
beforeMount
->onBeforeMount
mounted
->onMounted
- ์ด์ธ์๋
beforeCreate
์created
๋ผ์ดํ ์ฌ์ดํด์ด ์ ๊ฑฐ๋จ - ์๋ก ์ถ๊ฐ๋ ๋ผ์ดํ ์ฌ์ดํด ํ ์ ์๋์ ๊ฐ๋ค.
onRenderTracked
: ๋ ๋ ํจ์ ์์ ์กด์ฌํ๋ ๋ฆฌ์กํฐ๋ธ ๋ํ๋์๊ฐ ์ต์ด๋ก ์ ๊ทผ๋์์ ๋ ํธ์ถ๋๋ค. ๋๋ฒ๊น ์ ์ ์ฉํ ํonRenderTriggered
: ๋ ๋๋ง์ด ์๋ก ๋์์ ๋ ํธ์ถ๋๋ค. ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆฐ ์ด์ ๊ฐ ์ด๋ค๊ฑด์ง ๋๋ฒ๊น ํ๊ธฐ ์ข๋ค.
# VSCode ํ์ฅ ํ๋ฌ๊ทธ์ธ
- Vue VSCode Snippets (opens new window) : vbc(vbase-css)๋ฅผ ์น๊ณ ํญ์ ๋๋ฅด๋ฉด ์ปดํฌ๋ํธ ๊ธฐ๋ณธ ์ฝ๋๋ก ์๋ ์์ฑ