Vue 3 KeepAlive: cache de rotas, preservação de estado e controle de memória

前端工程(Atualizado em 15 de jul. de 2026)

<KeepAlive> é o componente integrado do Vue para cachear instâncias inativas. Ele é útil quando o usuário sai de uma página e volta esperando manter filtros, formulário, scroll e estado local de UI.

KeepAlive também é fácil de usar mal. Se todas as rotas forem cacheadas, a memória cresce. Se dados antigos nunca forem atualizados, usuários veem informações velhas. Se nomes de componentes e keys não forem controlados, o cache pode se comportar de forma inesperada.

Referências:

Quando vale usar KeepAlive

Use KeepAlive em páginas onde preservar estado local melhora o fluxo:

  • Lista com filtros, busca, abas e scroll.
  • Formulário multi-etapas em que o usuário pode visitar outra página e voltar.
  • Dashboard com renderização local cara.
  • Abas administrativas que não devem reiniciar.

Evite quando:

  • A página é barata de recriar.
  • Ela deve sempre mostrar dados novos.
  • Ela contém dados sensíveis que devem sumir ao sair.
  • O componente possui timers, subscriptions ou objetos grandes difíceis de pausar.

O padrão deve ser cache seletivo, não cachear todas as rotas.

Setup básico por rota

Vue Router expõe o componente renderizado pelo slot de RouterView. Esse é o lugar limpo para envolver páginas selecionadas com KeepAlive.

<!-- App.vue -->
<template>
  <RouterView v-slot="{ Component, route }">
    <KeepAlive :include="cachedComponentNames" :max="8">
      <component
        v-if="route.meta.keepAlive"
        :is="Component"
        :key="route.meta.cacheKey || route.name"
      />
    </KeepAlive>

    <component
      v-if="!route.meta.keepAlive"
      :is="Component"
      :key="route.fullPath"
    />
  </RouterView>
</template>

<script setup lang="ts">
const cachedComponentNames = ["UserList", "OrderList", "ReportDashboard"]
</script>

Metadados de rota mantêm a decisão perto da definição da rota.

// router.ts
import type { RouteRecordRaw } from "vue-router"

export const routes: RouteRecordRaw[] = [
  {
    path: "/users",
    name: "Users",
    component: () => import("./views/UserList.vue"),
    meta: {
      keepAlive: true,
      cacheKey: "users-list"
    }
  },
  {
    path: "/users/:id",
    name: "UserDetail",
    component: () => import("./views/UserDetail.vue"),
    meta: {
      keepAlive: false
    }
  }
]

Mantenha nomes de componentes estáveis ao usar include ou exclude, porque Vue faz match por nome.

<!-- UserList.vue -->
<script setup lang="ts">
defineOptions({
  name: "UserList"
})
</script>

Atualizar dados sem resetar UI

O bug mais comum são dados antigos. Uma página cacheada pode manter respostas antigas depois que o usuário volta.

Use onActivated para decidir se deve atualizar. Não recarregue tudo a cada ativação.

<script setup lang="ts">
import { onActivated, onDeactivated, ref } from "vue"

const users = ref<User[]>([])
const loading = ref(false)
const lastLoadedAt = ref(0)
const STALE_AFTER_MS = 60_000

async function loadUsers() {
  loading.value = true
  try {
    users.value = await fetchUsers()
    lastLoadedAt.value = Date.now()
  } finally {
    loading.value = false
  }
}

onActivated(() => {
  const isStale = Date.now() - lastLoadedAt.value > STALE_AFTER_MS
  if (!users.value.length || isStale) {
    void loadUsers()
  }
})

onDeactivated(() => {
  // Pause work that should not continue while the page is hidden.
})
</script>

Assim o estado local é preservado e os dados antigos são atualizados quando necessário.

Preservar scroll

KeepAlive preserva a instância, mas layout, transições e contêineres podem afetar o scroll.

<template>
  <main ref="scrollEl" class="page-scroll">
    <!-- list content -->
  </main>
</template>

<script setup lang="ts">
import { nextTick, onActivated, onDeactivated, ref } from "vue"

const scrollEl = ref<HTMLElement | null>(null)
let savedTop = 0

onDeactivated(() => {
  savedTop = scrollEl.value?.scrollTop ?? 0
})

onActivated(async () => {
  await nextTick()
  if (scrollEl.value) {
    scrollEl.value.scrollTop = savedTop
  }
})
</script>

Teste navegação direta, botão voltar e mudanças programáticas.

Controlar tamanho do cache

A prop max limita quantas instâncias KeepAlive mantém. Ao passar do limite, Vue remove entradas antigas.

<KeepAlive :max="8">
  <component :is="Component" />
</KeepAlive>

Escolha o limite com base em fluxos reais. Não use valor alto apenas para esconder problemas de estado.

Evitar vazamentos de memória

Componentes cacheados são desativados, não desmontados. Parte da limpeza fica em onDeactivated, e a limpeza final em onUnmounted.

Pause ou remova:

  • Intervals e timeouts.
  • Listeners WebSocket ou SSE que não devem rodar em background.
  • ResizeObserver e IntersectionObserver.
  • Listeners globais.
  • Arrays, maps ou blobs temporários grandes.
import { onActivated, onDeactivated, onUnmounted } from "vue"

let timer: number | undefined

function startPolling() {
  timer = window.setInterval(refreshStatus, 15_000)
}

function stopPolling() {
  if (timer) {
    window.clearInterval(timer)
    timer = undefined
  }
}

onActivated(startPolling)
onDeactivated(stopPolling)
onUnmounted(stopPolling)

Se a memória cresce após navegações repetidas, use devtools do navegador.

Cache keys e rotas dinâmicas

Rotas dinâmicas precisam de keys cuidadosas. Se páginas de detalhe usam o mesmo nome e a mesma key, podem compartilhar uma instância sem intenção.

<!-- Share one cached instance for the user list -->
<component :is="Component" :key="route.name" />

<!-- Separate cache entry for each route parameter -->
<component :is="Component" :key="route.fullPath" />

<!-- Controlled custom key -->
<component :is="Component" :key="route.meta.cacheKey || route.fullPath" />

Não use fullPath sem pensar em listas com muitas combinações de query. Isso pode criar entradas demais.

Regras práticas

Use KeepAlive quando a página tem estado local valioso. Não use como chave genérica de performance.

Bons candidatos:

  • Listas de busca.
  • Rascunhos de formulário.
  • Dashboards com charts caros.
  • Abas que devem alternar instantaneamente.

Maus candidatos:

  • Login e autenticação.
  • Pagamento ou páginas sensíveis.
  • Páginas que sempre precisam recarregar.
  • Detalhes com muitos IDs sem limite claro.

Checklist final

Antes de publicar:

  • Só rotas selecionadas usam KeepAlive.
  • Componentes cacheados têm nomes estáveis.
  • Rotas dinâmicas têm keys intencionais.
  • max é razoável.
  • Dados são atualizados com onActivated quando necessário.
  • Timers, observers e listeners pausam na desativação.
  • Páginas sensíveis não são cacheadas.
  • Botão voltar, navegação direta e abas foram testados.

KeepAlive é confiável quando tratado como preservação de estado, não como mágica automática de performance.

Experimente estas ferramentas executadas localmente no navegador — nenhum cadastro necessário →

#Vue3 KeepAlive#组件缓存#路由缓存#性能优化#include exclude#responsive component caching#layout template cache#2026#前端工程