1. 메타 컴포넌트
동적 컴포넌트를 랜더링하기 위해서 is prop에 의해 결정된다. 이를 메타 컴포넌트라고 한다.
1) 예제
<!-- is 속성에 해당되는 컴포넌트가 렌더링된다. -->
<component :is="componentId"></component>
<!-- 동적 컴포넌트는 등록된 컴포넌트나 prop로 전달된 컴포넌트를 렌더힝 할 수 있다. -->
<component :is="$options.components.child"></component>
<!-- 동적 컴포넌트는 문자열로 컴포넌트를 참조할 수 있다. -->
<component :is="condition ? 'HeaderComp' : 'FooterComp'"></component>
<!-- 동적 컴포넌트는 네이티브 HTML 엘리먼트를 렌더링 할 수도 있다. -->
<component :is="href ? 'a' : 'span'"></component>
2-1. 동적 컴포넌트
1) 컴포넌트 전환과 라이프 사이클
// About.vue
<template>
<div>
<h1>I'm About Component</h1>
</div>
</template>
<script>
export default {
name: 'About',
created() {
console.log('About component')
},
}
</script>
// Home.vue
<template>
<div>
<h1>I'm Home Component : 8</h1>
<button @click="addHomeCount()"> add home count </button>
</div>
</template>
<script>
export default {
name: 'Home',
created() {
console.log('Home component')
},
data() {
return { count : 0 }
},
methods: {
addHomeCount: function () {
this.count++
}
}
}
</script>
→ Home.vue와 About.vue는 create훅을 가져와 콘솔에 로그를 출력해준다.
// App.vue
<template>
<div id="app">
<a href="#" @click="changeComponent('Home')">Home;</a>
<a href="#" @click="changeComponent('About')">About</a>
<component v-bind:is="comp"></component> <!-- 선택한 컴포넌트 바인딩 -->
</div>
</template>
<script>
import Home from './components/keepAlive/Home'
import About from './components/keepAlive/About'
export default {
data() {
return { comp: 'Home' }
},
components: {
Home,
About,
},
methods: {
changeComponent: function(componentName) {
this.comp = componentName
}
}
}
</script>
→ 그리고 App.vue에서는 위의 두개의 컴포넌트를 가져온다. 그리고 클릭시 로그가 출력된다. 저기서 component는 해당 컴포넌트에서 작성한 것이 보여지는 것이다.
2) 컴포넌트 전환 실행 결과
실행 결과 화면을 보면 상단의 Home, About컴포넌트를 누르면 컴포넌트가 전환된다. 컴포넌트의 전환이 일어날 때마다 created 훅이 호출된다. 그리고 Home컴포넌트에서 add버튼을 눌렀을 때 데이터가 초기화된다는 것을 알 수 있다.
💡 즉, vue 인스턴스의 소멸, 생성이 반복된다는 것을 알 수 있다.
2-2. 동적 컴포넌트의 사용
컴포넌트를 전환할 때마다 페이지의 값이 초기화되어야 한다면 문제가 없겠지만 만약 컴포넌트 안에서 값을 유지 해야 하거나 성능상의 이유로 re-render를 피하고 싶다면 <keep-alive> 엘리먼트로 해결할 수 있다. keep-alive 로 둘러싼 컴포넌트는 컴포넌트가 최초 생성되는 시점에 캐시해 둔다.
// keep-alive : App.vue
<template>
<div id="app">
<a href="#" @click="changeComponent('Home')">Home;</a>
<a href="#" @click="changeComponent('About')">About</a>
<keep-alive>
<component v-bind:is="comp"></component>
</keep-alive>
</div>
</template>
<script>
import Home from './components/keepAlive/Home'
import About from './components/keepAlive/About'
export default {
data() {
return { comp: 'Home' }
},
components: {
Home,
About,
},
methods: {
changeComponent(view) {
this.comp = view
}
}
}
</script>
→ 위의 코드와 달라진 점은 component에 keep-alive로 component를 감싸주었다.
1) keep-alive 전
keep-alive 엘리먼트 없이 전환이 일어나는 컴포넌트는 전환이 일어날 때 마다 생성과 소멸을 반복하므로 Home.vue 의 data가 유지되지 않는다. 그렇기 때문에 버튼을 눌러 숫자가 달라지지만, 다른 컴포넌트에 다녀오면 count 가 다시 0부터 시작된다.
2) keep-alive 후
keep-alive 엘리먼트로 둘러 쌓인 컴포넌트는 최초 생성 시기에 (created) 캐시 되어 다른 컴포넌트에 다녀오더라도 페이지의 새로고침이 발생 하기 전까지 data의 상태가 유지된다.
2-3. exclude, include 속성 사용
<template>
<div>
<div class="header">
<h1 class="headerText">(주) OpenSG</h1>
<nav>
<ul>
<li>
<a href="#" @click="changeMenu('home')">Home</a>
</li>
<li>
<a href="#" @click="changeMenu('about')">About</a>
</li>
<li>
<a href="#" @click="changeMenu('contact')">Contact</a>
</li>
</ul>
</nav>
</div>
<div class="container">
<keep-alive include="about,home">
<component v-bind:is="currentView"></component>
</keep-alive>
</div>
</div>
</template>
<script>
import Home from './components/Home.vue';
import About from './components/About.vue';
import Contact from './components/Contact.vue';
export default {
name: 'App',
components : { Home, About, Contact },
data() {
return { currentView : 'home' }
},
methods : {
changeMenu(view) {
this.currentView = view;
}
}
}
</script>
<component> 요소에 v-bind:is로 currentView라는 data값을 바인딩했다. @click이벤트의 발생시마다 currentView의 값을 변경하여 <component>요소에 들어가는 컴포넌트 내용이 동적으로 변경됨을 알 수 있다.
실행 단계
⇒ 기본값으로 { currentView : 'home' }으로 되어 있다.
- keep-alive에 담긴 component를 확인한다. 그리고 나서 currenView가 담긴 것을 확인했다.
- templates에 li태그에 담긴 a태그를 확인한다. 이들을 클릭하면 함수를 실행하는 것을 알 수 있다.
- 함수는 view가 담아서 보내주는데, 이는 view가 currentView로 바뀐다.
기본적으로 매번 실행되기 때문에, 정적 콘텐츠 등을 가져올 때는 캐시해 두는 편이 좋다. 특정 컴포넌트만 캐싱하거나 캐싱하고 싶지 않다면 exclude, include 특성으로 컴포넌트들을 콤마로 구분하여 나열하면 된다.
- include에 포함된 컴포넌트들은 캐싱의 대상이 된다.
- exclude에 포함된 컴포넌트들은 캐싱 대상에서 제외된다.
- name옵션을 부여하지 않으면 컴포넌트명 기준으로 name을 인식한다.
- name은 대소문자를 구분한다.
나열하는 것은 지정된 이름이고, 이것은 자식 컴포넌트에서 export시 정의한 name 속성의 값과 동일하다.
💡 즉 여기서는 include에 about,home컴포넌트만 작성했으니 이들만 캐싱된다.