🌳 Vue의 <keep-alive>
와 캐싱 전략 완전정복
Vue 고급 시리즈 > 7️⃣ 고급 주제 및 최적화 > keep-alive와 캐싱 전략
- 1.
<keep-alive>
란? - 2. 기본 사용법 및 예제
- 3. include / exclude / max 옵션
- 4. activated / deactivated 훅
- 5. 탭 구조에서 캐싱 적용 예제
- 6. 주의사항 및 실전 전략
- 🔚 다음 글 안내
1. <keep-alive>
란?
<keep-alive>
는 Vue 내장 컴포넌트로, 컴포넌트를 메모리에 유지하여 다시 방문할 때 초기화되지 않고 이전 상태를 유지하게 해줍니다.
즉, 화면 전환 시 컴포넌트를 "언마운트"하지 않고, 비활성 상태로 두는 캐시 방식입니다. (created()나 mounted()가 재실행되지 않게 함)
- 탭 UI에서 컴포넌트 전환 시 이전 상태 유지
- 리스트/폼 화면 전환 시 스크롤 위치, 입력값 유지
- 라우터 전환 후 "뒤로가기" 시 데이터 재요청 방지
✅ 예시: 제품 목록 → 상세 보기 → 뒤로 가기 시, 목록 상태(페이지/스크롤 등)를 유지하고 싶을 때
2. 기본 사용법
<keep-alive>
<component :is="activeTab" />
</keep-alive>
→ 위 코드에서 activeTab
이 변경되면 이전 컴포넌트는 메모리에 보존된 채, 새로운 컴포넌트로 교체됩니다.
3. include / exclude / max 옵션
include
: 캐싱할 컴포넌트 이름 지정 (문자열 또는 정규식)exclude
: 캐싱 제외할 컴포넌트 이름max
: 최대 몇 개까지 컴포넌트를 메모리에 저장할지 제한
<keep-alive include="UserView,DashboardView" max="3">
<router-view />
</keep-alive>
4. activated / deactivated 훅
이 훅은 keep-alive
에서만 호출됩니다. ( keep-alive가 적용된 컴포넌트에서는 mounted 대신 activated, deactivated 훅을 사용함)
activated()
– 컴포넌트가 다시 보여질 때 호출deactivated()
– 캐시 상태로 빠질 때 호출
export default {
mounted() {
console.log("🚀 최초 1회만 실행"
),
activated() {
console.log("✅ 컴포넌트가 화면에 다시 나타날 때 실행");
},
deactivated() {
console.log("❌ 화면에서 사라질 때(비활성화시) 실행 (캐시 상태)");
}
}
📌 핵심: mounted는 최초 1회만, 이후에는 activated만 실행됩니다.
5. 실전 예제: 탭 구조 캐싱
탭 전환 시 이전 탭의 입력값, 스크롤 위치를 유지하고 싶을 때 유용합니다.
<template>
<div>
<button @click="current = 'Tab1'">Tab1</button>
<button @click="current = 'Tab2'">Tab2</button>
<keep-alive>
<component :is="current" />
</keep-alive>
</div>
</template>
<script>
import Tab1 from './Tab1.vue';
import Tab2 from './Tab2.vue';
export default {
components: { Tab1, Tab2 },
data() {
return { current: 'Tab1' }
}
}
</script>
✅ 결과: Tab1에서 작성한 입력값이 Tab2로 갔다가 돌아와도 유지됩니다.
1️⃣ 탭 구조에서의 <keep-alive>
적용
Vue로 탭 UI를 구현할 때 <keep-alive>
를 활용하면 각 탭의 컴포넌트 상태를 초기화하지 않고 유지할 수 있어 사용자 경험이 향상됩니다.
✅ 예시 시나리오:
- Tab1: 사용자 목록
- Tab2: 사용자 상세
- Tab3: 설정 폼
사용자가 Tab2로 이동했다가 Tab1으로 돌아와도 스크롤 위치, 입력 값 등이 유지되어야 하는 경우 유용합니다.
✅ 예제 코드:
<template>
<div>
<button @click="activeTab = 'Tab1'">Tab 1</button>
<button @click="activeTab = 'Tab2'">Tab 2</button>
<button @click="activeTab = 'Tab3'">Tab 3</button>
<keep-alive include="Tab1,Tab2,Tab3">
<component :is="activeTab" />
</keep-alive>
</div>
</template>
<script>
import Tab1 from './tabs/Tab1.vue';
import Tab2 from './tabs/Tab2.vue';
import Tab3 from './tabs/Tab3.vue';
export default {
components: { Tab1, Tab2, Tab3 },
data() {
return {
activeTab: 'Tab1'
}
}
}
</script>
🎯 팁:
<component :is>
패턴은keep-alive
와 함께 사용할 때 필수입니다.- 각 탭 컴포넌트에
activated()
/deactivated()
훅을 넣으면 탭 이동 시 실행 로직을 제어할 수 있습니다.
⚠ 주의사항:
- 탭을
v-if
또는v-show
로 토글하는 구조는keep-alive
의 캐싱 효과를 방해할 수 있습니다. - 동적 라우팅이 아닌 경우에도 탭 기반 전환은
component :is
를 통한 컴포넌트 전환으로 구성하는 것이 좋습니다.
🔄 캐시 초기화가 필요할 때:
특정 조건에서 캐시를 초기화하려면 :key
속성을 활용합니다.
<component :is="activeTab" :key="tabKey" />
→ tabKey
를 바꾸면 캐시를 강제로 초기화할 수 있습니다.
📌 실무 팁: 고객정보 입력, 설문조사, 탭 기반 설정 UI 등에서 <keep-alive>를 사용하면 UX가 매우 좋아집니다.
2️⃣ router-view 캐싱 (SPA 내 페이지 전환 시 상태 유지) :
라우트 컴포넌트를 캐싱하는 예제입니다. 탭이나 페이지 이동 시에도 상태가 유지
<template>
<keep-alive include="UserList,ProductList">
<router-view />
</keep-alive>
</template>
✅ 설명:
- UserList.vue, ProductList.vue는 캐싱되며, 목록 스크롤 위치나 form 입력값 등이 유지됨
- 그 외 컴포넌트는 캐싱되지 않음
💡 App.vue 혹은 MainLayout.vue에서 사용하면 효과적
컴포넌트 이름 기준으로 캐싱 동작
export default {
name: "UserList", // <- include 대상에 이 이름이 정확히 들어가야 함
data() {
return {
searchQuery: "",
items: []
};
},
activated() {
console.log("UserList 다시 활성화됨");
},
deactivated() {
console.log("UserList 비활성화됨 (캐시됨)");
}
};
💬 실전 팁:
- router-view 캐싱은 검색 화면, 리스트 페이지, 탭 뷰 등에서 효과적
- activated()에서 API를 재호출할지 여부를 조건으로 분기 가능 (예: 데이터 초기화 조건)
- <keep-alive :include="cachedViews">처럼 배열을 동적으로 관리할 수도 있음
data() {
return {
cachedViews: ["UserList", "ProductList"]
};
}
3️⃣ 조건부 캐싱 해제 (key를 활용한 강제 리렌더링):
특정 상황에서 <keep-alive>
로 캐싱된 컴포넌트를 초기화하고 싶을 때, :key
를 활용하면 컴포넌트를 강제로 재생성할 수 있습니다.
📌 예시: 검색 필터가 변경될 때마다 화면 초기화
예를 들어, 검색 조건이 바뀔 때 기존의 리스트 컴포넌트를 초기 상태로 재로드하고 싶다면:
<template>
<div>
<select v-model="searchType" @change="resetListKey">
<option value="A">타입 A</option>
<option value="B">타입 B</option>
</select>
<keep-alive>
<ItemList :type="searchType" :key="listKey" />
</keep-alive>
</div>
</template>
<script>
import ItemList from './ItemList.vue';
export default {
components: { ItemList },
data() {
return {
searchType: 'A',
listKey: 0
};
},
methods: {
resetListKey() {
this.listKey++; // key가 바뀌면 컴포넌트 재생성
}
}
}
</script>
✅ 동작 원리
:key
는 Vue가 컴포넌트를 재사용하지 않도록 만드는 핵심 수단입니다.- key가 바뀌면 기존 컴포넌트는 파괴(unmount)되고, 새롭게 생성됩니다.
- 이 방식은 캐시를 일부 조건에서만 무효화하고 싶을 때 매우 유용합니다.
⚠ 실전 팁
- 캐싱된 데이터를 강제로 초기화하고 싶을 때,
v-if
보다는:key
조작이 안전하고 권장됩니다. - 사용자 입력, 필터 변경, 페이지 초기화 등 특정 조건에서만 초기화가 필요할 때 이 패턴을 적용하세요.
✅ 실무에서는 keep-alive의 :key 속성에 임시값을 넣기도 하고, 의미있는 관리 단위를 넣기도 함
👉 1. 임시 count 값 (예: key++) 사용
💡 강제로 컴포넌트를 초기화(재생성) 하고 싶을 때 가장 많이 쓰는 방식입니다.
<keep-alive>
<MyComponent :key="key" />
</keep-alive>
<script>
export default {
data() {
return { key: 0 };
},
methods: {
resetComponent() {
this.key++; // key가 바뀌면 캐시 파기 + 재마운트
}
}
}
</script>
🔹 장점: 단순하고 컨트롤이 쉬움
🔹 사용처: 폼 초기화, 검색 조건 변경 시 화면 리셋 등
👉 2. 실제 의미 있는 키 값 사용 (예: route name, tab id 등)
💡 탭별로 컴포넌트를 구분해 캐싱하고 싶을 때 사용합니다.
<keep-alive :include="['PageA', 'PageB']">
<component :is="currentView" :key="currentView" />
</keep-alive>
<script>
export default {
data() {
return {
currentView: 'PageA' // 또는 route.name 등
};
}
}
</script>
🔹 장점: 의미 있는 키값으로 각 화면 캐싱 유지
🔹 사용처: 여러 탭 전환, 페이지 이동, 라우터 캐싱
📌 정리: 어떤 걸 쓸지 어떻게 판단할까?
강제로 캐시를 깨고 재생성 | key++ (임시 값) |
각 조건별로 개별 캐시 유지 | route.name, tabId |
상태 구분 없이 항상 새로 생성 | Date.now() 등 고유값 |
6. 주의사항 & 캐싱 전략
- 조건부 렌더링(
v-if
)은 캐싱을 방해할 수 있음 →<component :is>
패턴 추천 - 필요한 화면만 캐싱하려면
include
를 활용 ( 너무 많은 컴포넌트를 캐싱하면 메모리 누수) - 캐시 초기화가 필요할 땐
key
속성을 바꿔 컴포넌트를 강제 리렌더링 - 데이터 초기화 필요 시: activated에서 수동 초기화 처리
- vue-router와 함께 사용 시: meta: { keepAlive: true } 조건 기반 캐싱도 가능
- scrollBehavior: vue-router의 스크롤 위치 복원과 같이 쓰면 UX 향상
<component :is="currentView" :key="uniqueKey" />
⚠주의: keep-alive로 인해 mounted
훅은 재실행되지 않음 → activated
에서 다시 데이터 fetch 필요
🔚 다음 글 안내
이제 <keep-alive>
로 화면 전환 시 초기화 없이 부드러운 UX를 제공할 수 있게 되었어요.
다음 글에서는 Teleport를 활용한 모달 시스템 구성 방법을 살펴보겠습니다.
👉 다음 글: Teleport로 모달을 최상위에 위치시키기 – DOM 트리 외부로 컴포넌트를 이동시켜 UI를 깔끔하게 구성하는 방법을 알아봅니다.
'framework_library > vue' 카테고리의 다른 글
🌳 Composition API vs Options API - 무엇을 언제 써야 할까? (0) | 2025.05.05 |
---|---|
🌳 Vue의 Teleport로 모달 시스템 우아하게 구성하기 (0) | 2025.05.05 |
🌳Vue Suspense와 defineAsyncComponent - API 로딩 대기와 에러 핸들링 집중 탐구 (1) | 2025.05.05 |
📌 글로벌 컴포넌트 등록 전략 (0) | 2025.05.05 |
📌 커스텀 디렉티브 만들기 (v-focus, v-mask 등) (1) | 2025.05.05 |
댓글