
<KeepAlive>
는 <component>
컴포넌트와 함께 사용하면서 동적으로 바뀐 컴포넌트가 다시 사라지지 않게 도와주는 컴포넌트입니다. 어떻게 사용하는 지 자세히 알아볼까요?
KeepAlive 컴포넌트
Vue에는 컴포넌트를 is
속성에 따라 다르게 변경시켜주는 component
컴포넌트가 있습니다.
<component :is="compName" />
보통은 component가 바뀌면 당연히 원래 컴포넌트는 마운트 해제됩니다. 그리고 다시 해당 컴포넌트로 바꾸면 다시 처음부터 마운트가 되고 상태들이 초기화될겁니다. 공식 홈페이지에서는 KeepAlive를 사용한 예제가 있는데, 그 중 일부를 보겠습니다.
<script setup>
import { ref } from "vue";
import CompA from "./components/CompA.vue";
import CompB from "./components/CompB.vue";
const current = ref(CompA);
</script>
<template>
<div class="demo">
<label><input type="radio" v-model="current" :value="CompA" /> A</label>
<label><input type="radio" v-model="current" :value="CompB" /> B</label>
<component :is="current"></component>
</div>
</template>
이를 실행하면 다음과 같이 나옵니다.
component
컴포넌트로 A 컴포넌트로 바꾼 다음 count 값을 올렸습니다.component
컴포넌트로 B 컴포넌트로 바꾼 다음 “안녕”이란 글자를 적었습니다.component
로 다시 A 컴포넌트로 바꾸니 count가 초기값(0)으로 바뀌어있습니다.component
로 다시 B 컴포넌트로 바꾸니 글자가 사라졌습니다.컴포넌트가 바뀌니 당연히 기존 원래 것이 사라지고 다시 초기화되어 나타납니다. 하지만 이 경우는 기존 컴포넌트가 유지되어 원래 값을 유지하길 바랄겁니다. 이럴 땐 단순히 KeepAlive
컴포넌트에 넣어주기만 하면 됩니다.
<KeepAlive>
<component :is="current" />
</KeepAlive>
기존 컴포넌트가 마운트 해제 되지 않고 남아있는 것을 볼 수 있습니다.
만약 컴포넌트의template
속성을 쓰는 것이라면<keep-alive>
로 사용해야합니다.
Include로 포함할 것들 정하기
KeepAlive는 어떤 컴포넌트든 캐싱하여 마운트해제되지 않도록 해줍니다. 만일 어떤 컴포넌트는 남겨두길 원한다면 include
속성을 사용하면 됩니다.
<!-- 여러 개하는 경우 콤마(,)로 구분하면 됩니다. -->
<KeepAlive include="CompA,CompB">
<component :is="current" />
</KeepAlive>
<!-- v-bind + 정규식도 가능합니다. -->
<KeepAlive :include="/Comp.*/">
<component :is="current" />
</KeepAlive>
<!-- v-bind + 배열도 가능합니다. -->
<KeepAlive :include="['CompA', 'CompB']">
<component :is="current" />
</KeepAlive>
include에 포함되지 않는 컴포넌트들은 바뀌었을 때 자동으로 마운트 해제됩니다. 이 때 문자열과 비교하는 값은 컴포넌트의 name
속성입니다.
3.2.24 버전부터 <script setup> 은 자동으로 파일이름을 기준으로 name
값을 넣어줍니다.
exclude로 제외할 것들 정하기
반대로 exclude로 제외할 것들도 정할 수 있습니다.
<KeepAlive exclude="CompB">
<component :is="current" />
</KeepAlive>
이 경우 컴포넌트가 바뀌면 CompA
컴포넌트는 캐싱되어 유지되고 CompB
는 마운트해제 됩니다.
Include와 Exclude 같이 사용하기
물론 include
와 exclude
를 같이 사용할 수 있습니다. 정규식으로 Comp가 들어간 컴포넌트 중에 CompA만 빼고 유지되게 하는 예제입니다.
<KeepAlive :include="/Comp.*/" exclude="CompA">
<component :is="current"></component>
</KeepAlive>
캐싱 최대치 정하기
컴포넌트를 캐싱해두어 나중에 불러와도 내부 상태를 기억하는 것은 좋아보이지만, 기억해야둬야할 컴포넌트가 많을수록 성능에 문제가 생길 수 있습니다. 그래서 이를 max
속성으로 제한둘 수 있습니다.
<KeepAlive :max="5">
<component :is="current" />
</KeepAlive>
이 때 기억하는 방식은 LRU(Least recently used) 방식을 사용합니다. 이해를 돕기 위해 5개로 제한하고 A부터 E까지 컴포넌트를 차례대로 캐싱했다고 해보겠습니다.
[A, B, C, D, E]
여기서 F라는 새로운 컴포넌트를 캐싱해야한다면, 가장 오래전에 캐싱했던 A를 제거하고 F를 맨 뒤에 넣습니다.
// 오래된 A 제거하고 F를 캐싱
[B, C, D, E, F]
여기서 D를 다시 캐싱해야한다면 기존 것을 참조해서 맨 뒤에 넣습니다.
// 기존 D를 가장 최근으로 옮김
[B, C, E, F, D]
다시 정리하자면 max
속성을 정하면 LRU 방식으로 캐싱해서 기억해둡니다. 캐싱되지 않은 컴포넌트는 당연히 다시 새롭게 초기화 됩니다.
Activated 훅과 Deactivated 훅
컴포넌트를 캐싱해서 기억하니 마운트하는 것이 아니라 어디서 불러오는 것일 겁니다. 그래서 mounted
/ Unmounted
훅을 사용할 수 없습니다. 대신 Activated
/ Deactivated
훅을 사용하면 됩니다.
<template>
<p>Comp A</p>
</template>
<script setup>
import { onMounted, onUnmounted, onActivated, onDeactivated } from "vue";
onMounted(() => {
console.log("CompA Mounted");
});
onUnmounted(() => {
console.log("CompA Unmounted");
});
onActivated(() => {
console.log("CompA Activated");
});
onDeactivated(() => {
console.log("CompA Deactivated");
});
</script>
처음에 컴포넌트를 불러올 떄에는 mounted
와 activated
훅이 불러와지고 바뀌면서 deactivated
, activated
가 번갈아가면서 호출되는 것을 볼 수 있습니다.
만약 CompB가 CompA의 자식 컴포넌트로 들어갔다면 훅이 같이 호출되며 그 순서는 자식이 먼저입니다.
<template>
<p>
Comp A
<CompB />
</p>
</template>
<script setup>
import CompB from "./CompB.vue";
import { onMounted, onUnmounted, onActivated, onDeactivated } from "vue";
onMounted(() => {
console.log("CompA Mounted");
});
onUnmounted(() => {
console.log("CompA Unmounted");
});
onActivated(() => {
console.log("CompA Activated");
});
onDeactivated(() => {
console.log("CompA Deactivated");
});
</script>