본문 바로가기
framework_library/vue

🌳 Vue의 <keep-alive>와 캐싱 전략 완전정복

by 죄니안죄니 2025. 5. 5.

🌳 Vue의 <keep-alive>와 캐싱 전략 완전정복

Vue 고급 시리즈 > 7️⃣ 고급 주제 및 최적화 > keep-alive와 캐싱 전략


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를 깔끔하게 구성하는 방법을 알아봅니다.

댓글