Intro
์๋ ํ์ธ์. ๊ฐ๋ฐ์ ์์ฑ๋น์ ๋๋ค. ์ต๊ทผ์ Vue.js ๊ณต๋ถ๋ฅผ ์์ํ์ต๋๋ค. ์๋กญ๊ฒ ๋ฐฐ์ด ๋์ด๋ ๋ฐ๋ก ์จ๋จน๊ณ ์ถ์ด ๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ ์์ํ์ฃ . ํ๋ก์ ํธ ์ ๋ชฉ์ 'everything', '๋์๋ณด๋ ์์ ์๊ฐ๋๋ ๋ชจ๋ ๊ฒ์ ์ฌ๋ ค๋ณด์'๋ผ๋ ์์ด๋์ด๋ฅผ ๋ฐํ์ผ๋ก ์ฐจ๊ทผ์ฐจ๊ทผ ์งํํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ค ๋ง๋ 'Dynamic components', ๋์ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌํํ๋ฉด์ ๊ฒช์๋ ๊ฒ๋ค์ ์ค๋ ์ ์ด๋ณด๋ ค ํฉ๋๋ค.
Result
<template>
<div class="hello">
<!-- ... -->
<component :is="componentLoader"></component>
</div>
</template>
export default{
// ...
data() {
return {
// ...
, currentTab: 'VueRouter'
}
},
computed: {
componentLoader() {
const tab = this.currentTab
return () =>import(`@/components/${tab}`)
}
}
}
currentTab ๋ณ์์ ๋ค์ด๊ฐ๋ String ๊ฐ์ ๋ฐ๋ผ์ componentLoader๊ฐ ๋์ํฉ๋๋ค.
componentLoader๋ currentTab์ ๋ง๋ ์ปดํฌ๋ํธ๋ฅผ ๋์ ์ผ๋ก import.
๊ฒฐ๊ณผ์ ์ผ๋ก <component> ํ๊ทธ ์๋ฆฌ์ ์ํ๋ ์ปดํฌ๋ํธ๊ฐ ์์ฑ๋ฉ๋๋ค.
์ ์ฒด ์์ค ์ฝ๋๋ ์ด๊ณณ์์ ํ์ธ ๊ฐ๋ฅํ์ญ๋๋ค.
์ฃผ์ ๋ฆฌ์ฃผ์ ๋ฆฌ

'everything'์ ๊ตฌํ๋ ๊ธฐ๋ฅ ์ค ํ๋์ธ 'Memo' ๊ธฐ๋ฅ์ ๋ชจ์ต์ ๋๋ค. 'Memo' ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ฉ๋ชจ์ฅ์ด ๋์๋ณด๋ ์์ ์ถ๊ฐ๋๋ ๊ธฐ๋ฅ์ ๋๋ค. ์ง๊ธ์ 'Memo' ๋ฐ์ ์์ง๋ง '๋ฌ๋ ฅ'์ด๋ '๋ ์จ' ๋ฑ์ ์ถ๊ฐํด ๋๊ฐ ๊ณํ์ ๋๋ค. ์ด๋ ๊ฒ ์ถ๊ฐ๋๋ ๊ธฐ๋ฅ๋ค์ ๋ชจ๋ ํ๋ฉด ์๋ฅผ ์์ ๋กญ๊ฒ ๋ ๋ค๋๋ Floating ๊ธฐ๋ฅ์ ๊ณตํต์ผ๋ก ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ทธ๋์ ์ ๋ ์ด๊ฑธ Widget์ด๋ผ๊ณ ๋ถ๋ฅด๊ธฐ๋ก ํ์ต๋๋ค.

Widget ์ปดํฌ๋ํธ๋ Floating ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํ์ง๋ง ๊ทธ๊ฒ ๋ง๊ณ ๋ ์๋ฌด๊ฒ๋ ์์ต๋๋ค. ๋ ๋ค๋๋ ์ ๋น ๊ฐ์ ์ด๋๊น์? ํ์ง๋ง ๊ทธ ๋น ๊ณต๊ฐ์ ๋์ ์ปดํฌ๋ํธ(Dynamic Components)๋ฅผ ๊ตฌํํ๋ค๋ฉด ๋ญ๋ ๋ ๋ค๋๋ ์์ ฏ์ด ๋ง๋ค์ด์ง๊ฒ ์ฃ .
๊ตฌํ
new Vue({
// ...
components: {
"my-component": () => import("./my-async-component")
}
});
Vue ๊ณต์ ํํ์ด์ง์์ ์๋ดํ๋ ๋์ ์ปดํฌ๋ํธ ๊ตฌํ ์์์ ๋๋ค. ์ด๋ ๊ฒ ํด๋๋ฉด ํด๋น ์ปดํฌ๋ํธ๊ฐ ํ์ํ ๋ ๋์ ์ผ๋ก ๋ก๋๋๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์์ ์ด์ ์ ๊ฐ์ง ์ ์๋ค๊ณ ์๋ ค์ฃผ๊ณ ์์ต๋๋ค. ํ์ง๋ง ์ด๊ฑด ์ ๊ฐ ์ํ๋ ๋ฐฉ์์ ์๋์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด

export default{
// ...
components: {
VueRouter: () => import('@/components/VueRouter'),
Vuex: () => import('@/components/Vuex'),
VueDevtools: () => import('@/components/VueDevtools'),
}
}
์ด๋ ๊ฒ n๊ฐ์ ์ปดํฌ๋ํธ, ์ฆ ์์ ฏ๋ค์ด ๋ง๋ค์ด์ง๋ค๋ฉด n๋ฒ ๋ฐ๋ณตํ์ฌ components์ ๋ฑ๋กํด์ค์ผ ํฉ๋๋ค. ๋ฌผ๋ก ํ์ค์ ์ผ๋ก ์๊ฐํ๋ฉด 'evrerything'์ ์์ ํ๋ก์ ํธ์ด๋ ์ด๊ฒ๋ง์ผ๋ก๋ ์ถฉ๋ถํ ์๋ ์๊ฒ ์ง๋ง... ๊ฐ์ ์ฝ๋๋ฅผ n๋ฒ ๋ฐ๋ณตํ๋ผ๋จ. ์ซ์ต๋๋ค!
๊ทธ๋์ ์ฐพ์์ต๋๋ค! ์ง์~
<template>
<!-- ... -->
<li
...
@click="currentTab = tab">
{{ tab }}
</li>
<!-- ... -->
<component:is="componentLoader"></component>
</template>
export default{
// ...
data() {
return {
// ...
, currentTab: 'VueRouter'
}
},
computed: {
componentLoader() {
return () => import(`@/components/${this.currentTab}`)
}
}
}
computed๋ฅผ ํ์ฉํ ๋์ ์ปดํฌ๋ํธ ๋ฐฉ์. ์์ ๋ณด์ฌ๋๋ฆฐ ๋ฐฉ์๊ณผ ๋น์ทํด ๋ณด์ด์ง๋ง n๊ฐ์ ์์ ฏ์ด ์๊ธด๋ค๊ณ ํ๋๋ผ๊ณ props๋ data๋ฅผ ํ์ฉํด ํ๋์ ํจ์๋ก ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๊ฒ ๋์์ฃ . ์ด์ ์ ๊ฐ ์๊ฐํ๋ '๋์ ์ปดํฌ๋ํธ'๊ฐ ๋์์ต๋๋ค. ํ์ง๋ง!! ๋๋์ฒด ์! ํ ๋ฒ์ ๋๋ ๊ฒ ์์๊น์.

currentTab์ ๊ฐ์ ์ ๋๋ก ๋ณํ๊ณ ์์ต๋๋ค๋ง ์ด์ํ๊ฒ computed๋ฅผ ํ์ฉํ ๋ฐฉ์์ ๋์ํ์ง ์์ต๋๋ค. ๊ทธ๋ ๊ฒ ์ด์ ๊ฐ ๋ญ๊น ํ๋ฉฐ ์ด๊ฒ์ ๊ฒ ํด๋ณด๋ค๊ฐ ์ฐพ์๊ฑด computed์ ํน๋ณํจ์ด์์ต๋๋ค.
export default{
// ...
data() {
return {
// ...
, currentTab: 'VueRouter'
}
},
computed: {
componentLoader() {
console.log(this.currentTab)
return () =>import(`@/components/${this.currentTab}`)
}
}
}
๋ง์ฝ ์ด๋ ๊ฒ componentLoader ํจ์์ ์ ํ ์๋ฏธ ์๋ console.log๋ฅผ ์ถ๊ฐํ๋ฉด ์ด๋จ๊น์?

๋๋๊ฒ๋ ์ด๋ ๊ฒ ์ ์์ ์ผ๋ก ์๋ํ๊ฒ ๋ฉ๋๋ค.
vue์ computed๋ ์บ์ฑ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ์์ ์ด ์ฐธ์กฐํ๊ณ ์๋ data์ ๊ฐ์ด ๋ณํ์ง ์์๋ค๋ฉด ์บ์ฑ๋ ๊ฐ์ ๊บผ๋ด์ returnํ๋ ๊ธฐ๋ฅ์ด์ฃ . ์ ํฌ ๋์ผ๋ก ๋ณด๊ธฐ์ componentLoader๊ฐ currentTab์ ์ฐธ์กฐํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์ค์ ๋ก ๊ทธ๋ ์ง ๋ชปํด ๋์์ ํ์ง ์์๋ ๊ฒ์ด์ฃ .

์ด ๋ถ๋ถ์ ์ด์ผ๊ธฐํ๊ธฐ ์ํด์ computedWatchers ์์ฑ์ ๋ํด ์์๋ด์ผ ํฉ๋๋ค. ํ์ง๋ง ์ด๊ฑด Vue์ Reactivity ์์คํ ๊ณผ ๊ด๋ จ์ด ์์ต๋๋ค. Vue์ Reactivity ์์คํ ์ ์ด์ผ๊ธฐ๋ฅผ ์ฌ๊ธฐ์ ํ์ด๋ด๊ธฐ์ ์ ๋น์ด ์ด ๊ธ์ ์ฃผ์ ์ ์กฐ๊ธ ๋ฒ์ด๋๋ ๊ฒ ์๋๊ฐ ์ถ์ด ๋ค๋ฅธ ๊ธ์ ์ ์ด๋๊ฒ ์ต๋๋ค. ํน์ ๊ด์ฌ์ด ์์ผ์๋ค๋ฉด ๊ผญ ๋ด์ฃผ์ธ์.
๊ทธ๋ ๋ค๋ฉด ์ผ๋จ!!
console.log ๋์ ์๋์ฒ๋ผ ๋ฐ๊พธ๋ฉด
export default{
// ...
data() {
return {
// ...
, currentTab: 'VueRouter'
}
},
computed: {
componentLoader() {
const tab = this.currentTab
return () =>import(`@/components/${tab}`)
}
}
}
Dynamic component ๋!!!
๋๊ธ