Vue.js: Ciclo de Vida do Componente

Última atualização: 2026-08-26

O ciclo de vida de um componente é todo o processo pelo qual um componente Vue passa, desde a criação até a destruição: instanciação → montagem no DOM → atualizações de dados → desmontagem. O Vue oferece oito ganchos de ciclo de vida que permitem executar código em momentos específicos.

Compreender o ciclo de vida é fundamental para escrever componentes “dinâmicos” — é possível carregar dados na montagem, executar efeitos colaterais na atualização e liberar recursos na desmontagem.

1. O que você vai aprender


2. Um problema de “oscilação” em um componente de carregamento de dados

(1) Problema: O componente foi renderizado, mas os dados ainda não foram carregados

Alice criou um componente de perfil de usuário:

VUE
<!-- ❌ The "Broken" Version:Rendering Before Data Arrives -->
<template>
  <div>
    <h1>{{ user.name }}</h1>
    <p>{{ user.email }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const user = ref({})  // Empty object,Display during rendering "undefined"
fetch('/api/user')
  .then(res => res.json())
  .then(data => user.value = data)
</script>

Experiência do usuário:

O gerente de produto Charlie:

“Alice, os usuários veem ‘indefinido’ por meio segundo. Precisamos de um indicador de carregamento. Mostre ‘Carregando...’ até que os dados cheguem.”

(2) Ciclo de vida do Vue + Solução para o estado “Carregando”

VUE
<template>
  <div>
    <p v-if="loading">Loading...</p>
    <div v-else>
      <h1>{{ user.name }}</h1>
      <p>{{ user.email }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const user = ref(null)
const loading = ref(true)

// ✅ Load data in onMounted... (DOM Ready, loading status will be displayed first)
onMounted(async () => {
  const res = await fetch('/api/user')
  user.value = await res.json()
  loading.value = false
})
</script>

Experiência do usuário:

(3) Receita

Após adicionar o ciclo de vida:


3. Fluxograma do ciclo de vida completo

100%
graph TB
    A[Create a component instance] --> B[onBeforeCreate]
    B --> C[setup Responsive]
    C --> D[onCreated]
    D --> E[Template Compilation]
    E --> F[onBeforeMount]
    F --> G[Mount to DOM]
    G --> H[onMounted]
    H --> I{Data Update?}
    I -->|Yes| J[onBeforeUpdate]
    J --> K[Render Again]
    K --> L[onUpdated]
    L --> I
    I -->|No| M{Component Uninstall?}
    M -->|Yes| N[onBeforeUnmount]
    N --> O[Unmount]
    O --> P[onUnmounted]
    
    style H fill:#42b883,color:#fff
    style L fill:#42b883,color:#fff
    style P fill:#42b883,color:#fff

4. Uma explicação detalhada dos 8 ganchos do ciclo de vida

(1) Referência rápida aos 8 principais ganchos

Hook Condições de acionamento Cenários comuns Frequência
onBeforeMount Antes da montagem dos componentes Preparar os dados
onMounted Após a montagem do componente Carregamento de dados, operações no DOM ⭐⭐⭐⭐⭐
onBeforeUpdate Antes da atualização dos dados Otimização de desempenho ⭐⭐
onUpdated Após a atualização dos dados Operações após a reexibição do DOM ⭐⭐⭐
onBeforeUnmount Antes de retirar um componente Zerar os temporizadores ⭐⭐⭐
onUnmounted Após desinstalar o componente Limpeza final ⭐⭐
onErrorCaptured Erro no componente filho Limite de erro ⭐⭐⭐
onActivated Keep-Alive ativado Componente de cache restaurado ⭐⭐
onDeactivated keep-alive desativado componente de cache desativado ⭐⭐

(2) onMounted: O mais utilizado

VUE
<script setup>
import { ref, onMounted } from 'vue'

const user = ref(null)

onMounted(async () => {
  // 1. Loading initial data
  const res = await fetch('/api/user')
  user.value = await res.json()
  
  // 2. DOM Operations(Realistic operation DOM)
  document.title = `${user.value.name} - Dashboard`
  
  // 3. Register a global event listener
  window.addEventListener('resize', handleResize)
  
  // 4. Set a Timer
  const timer = setInterval(() => {
    console.log('Tick')
  }, 1000)
  
  // ❌ Note: onUnmounted must clean up timer and listener
})
</script>

(3) onUnmounted: Liberar recursos

VUE
<script setup>
import { onMounted, onUnmounted } from 'vue'

let timer = null

onMounted(() => {
  timer = setInterval(() => console.log('Tick'), 1000)
  window.addEventListener('resize', handleResize)
})

// ✅ Cleanup:Avoiding Memory Leaks
onUnmounted(() => {
  clearInterval(timer)
  window.removeEventListener('resize', handleResize)
})
</script>

(4) onErrorCaptured: Limite de erro

VUE
<!-- ErrorBoundary.vue Parent Component -->
<script setup>
import { onErrorCaptured, ref } from 'vue'

const error = ref(null)

onErrorCaptured((err, instance, info) => {
  console.error('Caught error:', err)
  console.log('Component:', instance)
  console.log('Info:', info)
  
  error.value = err.message
  return false  // Prevent errors from propagating upward
})
</script>

<template>
  <div>
    <p v-if="error" class="error">Error: {{ error }}</p>
    <slot v-else />
  </div>
</template>
VUE
<!-- App.vue Usage -->
<ErrorBoundary>
  <UserProfile :user-id="123" />  <!-- If an error occurs, will be caught by ErrorBoundary -->
</ErrorBoundary>

(5) 5 principais casos de uso

Cenário Gancho Código
Carregando dados iniciais onMounted await fetch(...)
Definir temporizador onMounted + onUnmounted setInterval + clearInterval
Fique atento aos eventos globais
Manipulação do DOM onMounted document.querySelector(...)
Integração de bibliotecas de terceiros onMounted + onUnmounted new Chart(...) + chart.destroy()

5. Ordem de execução dos ciclos de vida dos componentes pai e filho

(1) Ordem de montagem

100%
sequenceDiagram
    participant P as Parent
    participant C as Child
    
    P->>P: 1. Parent onBeforeMount
    P->>P: 2. Parent onMounted
    C->>C: 3. Child onBeforeMount
    C->>C: 4. Child onMounted
    
    Note over P,C: ❌ That's wrong: Parent mounted should come after Child

Ordem correta:

100%
sequenceDiagram
    participant P as Parent
    participant C as Child
    
    P->>P: 1. Parent onBeforeMount
    C->>C: 2. Child onBeforeMount
    C->>C: 3. Child onMounted
    P->>P: 4. Parent onMounted
    
    Note over P,C: ✅ Mount only after all child components, including the parent component, have finished mounting

(2) Ordem de execução completa (componentes aninhados)

TEXT 📖 Somente leitura
1. Parent onBeforeCreate
2. Parent setup
3. Parent onCreated
4. Parent onBeforeMount
5. Child onBeforeCreate
6. Child setup
7. Child onCreated
8. Child onBeforeMount
9. Child onMounted
10. Parent onMounted

(3) Ordem de desinstalação (na ordem inversa)

TEXT 📖 Somente leitura
1. Parent onBeforeUnmount
2. Child onBeforeUnmount
3. Child onUnmounted
4. Parent onUnmounted

6. Componente de cache Keep-Alive

(1) O que é o keep-alive?

<keep-alive> Armazena instâncias de componentes em cache para evitar a criação e destruição repetidas. É comumente usado em cenários que envolvem alternância entre abas e troca de rotas.

VUE
<!-- Parent Component -->
<template>
  <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">
    {{ tab }}
  </button>
  
  <!-- keep-alive Package:Switch Tab Do not destroy the component -->
  <keep-alive>
    <component :is="currentTabComponent" />
  </keep-alive>
</template>

(2) 2 novos ganchos

VUE
<!-- Child component: Cached by keep-alive -->
<script setup>
import { onActivated, onDeactivated } from 'vue'

// When the component is activated(Restore from Cache)
onActivated(() => {
  console.log('Component activated')
  // Reload Data、Restore scroll position, etc.
})

// When a component is disabled(Cut but keep in cache)
onDeactivated(() => {
  console.log('Component deactivated')
  // Save Status、Pause the timer, etc.
})
</script>

(3) 5 principais casos de uso

Cenário Método
Alternar entre abas <keep-alive> Quebrar o conteúdo da aba
Mudança de rota Pacote <keep-alive> <router-view>
Cache pop-up <keep-alive> Janela pop-up do pacote
Página da lista Listas carregadas em cache
Página do formulário Armazenar em cache os formulários não enviados

7. Exemplo completo: Componente de perfil do usuário

▶ Exemplo: 1. onMounted + onUnmounted (carregamento de dados + limpeza)

VUE
<template>
  <div>
    <p v-if="loading">Loading...</p>
    <div v-else-if="user">
      <h1>{{ user.name }}</h1>
      <p>{{ user.email }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const props = defineProps({ userId: { type: Number, required: true } })
const user = ref(null)
const loading = ref(true)

let timer = null

onMounted(async () => {
  // 1. Loading data
  const res = await fetch(`/api/users/${props.userId}`)
  user.value = await res.json()
  loading.value = false
  
  // 2. Set a Timer (Every 30s Refresh)
  timer = setInterval(async () => {
    const res = await fetch(`/api/users/${props.userId}`)
    user.value = await res.json()
  }, 30000)
  
  // 3. Monitoring Window Size Changes
  window.addEventListener('resize', () => {
    console.log('Window resized')
  })
})

onUnmounted(() => {
  // ✅ Cleanup:Avoiding Memory Leaks
  clearInterval(timer)
  window.removeEventListener('resize', () => {})
})
</script>
▶ Experimente

▶ Exemplo: 2. Referência rápida para 8 ganchos

VUE
<script setup>
import { 
  onBeforeMount, onMounted, 
  onBeforeUpdate, onUpdated,
  onBeforeUnmount, onUnmounted,
  onErrorCaptured, onActivated, onDeactivated 
} from 'vue'

// 1. Before Mounting
onBeforeMount(() => {
  console.log('1. Preparing to mount')
})

// 2. After mounting(Most Commonly Used)
onMounted(() => {
  console.log('2. Mounted,Loading data')
})

// 3. Before the update
onBeforeUpdate(() => {
  console.log('3. Coming Soon')
})

// 4. After the update
onUpdated(() => {
  console.log('4. Updated')
})

// 5. Before Uninstalling
onBeforeUnmount(() => {
  console.log('5. Preparing to uninstall,Free Up Resources')
})

// 6. After uninstallation
onUnmounted(() => {
  console.log('6. Uninstalled')
})

// 7. Error Handling
onErrorCaptured((err) => {
  console.error('7. Child Component Error:', err)
  return false
})

// 8. keep-alive Activate
onActivated(() => {
  console.log('8. keep-alive Activate')
})

// 9. keep-alive Disable
onDeactivated(() => {
  console.log('9. keep-alive Disable')
})
</script>
▶ Experimente

▶ Exemplo: 3. Ordem do ciclo de vida dos componentes pai e filho

VUE
<!-- Parent.vue -->
<template>
  <Child :data="parentData" />
</template>

<script setup>
import { onMounted } from 'vue'
onMounted(() => console.log('4. Parent mounted'))
</script>

<!-- Child.vue -->
<template>
  <p>{{ data }}</p>
</template>

<script setup>
import { onMounted } from 'vue'
onMounted(() => console.log('3. Child mounted'))
</script>

<!-- Order of Console Output:
1. Child created
2. Child mounted
3. Parent mounted
(Because the parent component must wait until the child component has finished mounting before it can mount itself) -->
▶ Experimente

▶ Exemplo: 4. Limite de erro onErrorCaptured

VUE
<!-- ErrorBoundary.vue -->
<script setup>
import { onErrorCaptured, ref } from 'vue'

const error = ref(null)

onErrorCaptured((err, instance, info) => {
  console.error('Caught error:', err)
  console.log('Component:', instance?.$options.name)
  console.log('Info:', info)  // 'render' / 'watch' / 'lifecycle hook'
  
  error.value = err.message
  return false  // Prevent upward transmission
})
</script>

<template>
  <div v-if="error" class="error-banner">
    ⚠️ Error: {{ error }}
  </div>
  <slot v-else />
</template>
▶ Experimente

▶ Exemplo: 5. Componente de cache keep-alive

VUE
<!-- TabContainer.vue -->
<template>
  <div class="tabs">
    <button 
      v-for="tab in tabs" 
      :key="tab"
      :class="{ active: currentTab === tab }"
      @click="currentTab = tab"
    >
      {{ tab }}
    </button>
    
    <!-- keep-alive Cache: Preserve component state when switching away -->
    <keep-alive>
      <component :is="currentTabComponent" />
    </keep-alive>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import Home from './tabs/Home.vue'
import Profile from './tabs/Profile.vue'
import Settings from './tabs/Settings.vue'

const tabs = ['Home', 'Profile', 'Settings']
const currentTab = ref('Home')

const currentTabComponent = computed(() => {
  return { Home, Profile, Settings }[currentTab.value]
})
</script>
▶ Experimente

▶ Exemplo: 6. Referência rápida para 5 erros comuns

Erro Sintoma Solução
Use document no nível superior de setup Erro do servidor Use onMounted
Temporizador não foi liberado Vazamento de memória Limpar em onUnmounted
Modificar props no onMounted Aviso do Vue Use emit em vez disso
Componentes assíncronos não tratam erros Falha silenciosa onErrorCaptured
Ordem incorreta de montagem pai-filho Confusão na depuração Compreendendo o princípio “pai é igual a filho”

❓ Perguntas Frequentes

P: Qual é a diferença entre onMounted e onCreated? R: Quando onCreated é chamado, o componente já foi criado, mas o DOM ainda não foi renderizado (portanto, não é possível manipular o DOM). Quando onMounted é chamado, o DOM já foi montado (portanto, é possível manipular o DOM). O carregamento de dados geralmente é tratado em onMounted (para evitar problemas de SSR).

P: Os hooks de ciclo de vida podem ser assíncronos? R: Sim. onMounted(async () => { await fetch(...) }) é uma sintaxe válida. O Vue não espera que a operação assíncrona seja concluída antes de continuar.

P: Qual é a diferença entre onActivated e onMounted em keep-alive? R: onMounted é acionado apenas uma vez (na montagem inicial). onActivated é acionado toda vez que a visualização é restaurada do cache. A troca de abas aciona onActivated e onDeactivated (não onMounted e onUnmounted).

P: Que tipos de erros o onErrorCaptured pode capturar? R: Ele pode capturar três tipos: (1) erros de renderização de componentes filhos; (2) erros nos ganchos do ciclo de vida de componentes filhos; (3) erros nos callbacks de observação de componentes filhos. No entanto, ele não pode capturar seus próprios erros nem erros assíncronos.

P: Um componente pai pode monitorar os eventos do ciclo de vida de um componente filho? R: Sim. Você pode usar @hook para monitorar: @hook:mounted="handleChildMounted". No entanto, recomenda-se usar props/emit para a comunicação, em vez de monitorar diretamente os eventos do ciclo de vida.

P: Quais são as diferenças entre os hooks de ciclo de vida do Vue 2 e do Vue 3? R: O Vue 3 renomeou o hook para onMounted (que era mounted no Vue 2) e adicionou onErrorCaptured e onActivated/onDeactivated. Todos os ganchos do Vue 2 estão disponíveis no Vue 3 (a compatibilidade com versões anteriores é mantida).

P: O que acontece com o ciclo de vida durante a SSR (renderização no lado do servidor)? R: onBeforeMount, onMounted, onBeforeUpdate e onUpdated não são acionados no servidor (já que não há DOM). Apenas onBeforeCreate, onCreated, onBeforeUnmount, onUnmounted e onErrorCaptured são acionados.


📖 Resumo


📝 Exercícios

  1. Questões básicas (Dificuldade: ⭐)

    Implemente um componente UserCard simples:

    • onMounted: Carregar os dados do usuário (simular um atraso de 1 segundo)
    • Mostrar “Carregando” → Mostrar informações do usuário
    • em registros de desmontagem: “Componente destruído”
  2. Problemas avançados (Dificuldade: ⭐⭐)

    Implementar um componente Timer:

    • onMounted: Inicia um cronômetro (+1 por segundo)
    • Exibir o segundo atual
    • onUnmounted: Limpar o temporizador
    • Adicione um botão para pausar/retomar (use ref para salvar o estado)
  3. Problema desafiador (Dificuldade: ⭐⭐⭐)

    Implementar um sistema completo de abas:

    1. TabContainer.vue: 3 abas (Página inicial/Perfil/Configurações)
    2. 3 componentes de conteúdo em abas
    3. Utilize o componente de cache <keep-alive>
    4. Alterar a saída da guia “X ativado, Y desativado”
    5. Carregue os dados em uma das abas usando onMounted
    6. A conexão não é encerrada ao sair da página (devido ao keep-alive), portanto, os dados ainda estão lá ao voltar à página
    7. Use onErrorCaptured para detectar erros nos componentes filhos
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%