Vue.js: Componentes Dinâmicos e Assíncronos

Última atualização: 2026-10-20

Os componentes dinâmicos permitem que você renderize dinamicamente diferentes componentes usando uma única tag <component> — alternando entre abas, janelas modais e visualizações route com base nos dados. Os componentes assíncronos permitem que você carregue componentes sob demanda — carregando apenas o código necessário na primeira tela para melhorar o desempenho.

O componente experimental <Suspense> do Vue 3 foi projetado especificamente para lidar com o estado de carregamento de componentes assíncronos, eliminando a necessidade de escrever manualmente v-if="loading". Esta lição ajudará você a dominar três APIs principais.

Diretivas relacionados:v-if

1. O que você vai aprender


2. O pesadelo das 5 instruções “v-if” em uma única aba

(1) Problema: 5 guias, 10 diretivas v-if aninhadas

Alice criou um painel de administração com abas:

O gerente de produto Charlie:

“Alice, precisamos de mais 5 abas. 10 linhas de v-if-else são impossíveis de manter. Use um componente dinâmico.”

(2) Solução com componentes dinâmicos do Vue: 1 <component> para alternar entre 5 abas

VUE
<!-- ✅ Correct Version: 1 <component> Switch -->
<template>
  <div class="tabs">
    <button 
      v-for="tab in tabs" 
      :key="tab.name"
      :class="{ active: currentTab === tab.name }"
      @click="currentTab = tab.name"
    >
      {{ tab.label }}
    </button>
    
    <!-- ✅ 1 <component> Dynamic Tag Switching -->
    <component :is="currentTabComponent" />
  </div>
</template>

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

// Synchronization Components
import HomeTab from './tabs/HomeTab.vue'
import ProfileTab from './tabs/ProfileTab.vue'

// Asynchronous Components(Laden on Demand)
const SettingsTab = defineAsyncComponent(() => import('./tabs/SettingsTab.vue'))

const tabs = [
  { name: 'home', label: 'Home' },
  { name: 'profile', label: 'Profile' },
  { name: 'settings', label: 'Settings' }
]

const currentTab = ref('home')

// Computed Properties:According to currentTab Determine which component to display
const currentTabComponent = computed(() => {
  return { home: HomeTab, profile: ProfileTab, settings: SettingsTab }[currentTab.value]
})
</script>

(3) Receita

Após utilizar componentes dinâmicos:


3. <component :is="..."> Noções básicas

(1) 5 maneiras de usar :is

VUE
<!-- Writing Style 1:Component Name String(Registered globally) -->
<component :is="'HomeTab'" />

<!-- Writing Style 2:Component Object(Most Commonly Used) -->
<component :is="HomeTab" />

<!-- Writing Style 3:Dynamically Calculated Properties -->
<component :is="currentTabComponent" />

<!-- Writing Style 4:Asynchronous Component Object -->
<component :is="asyncComponent" />

<!-- Writing Style 5:Inline Component Object -->
<component :is="{ template: '<div>Inline</div>' }" />

(2) Exemplo completo

VUE
<!-- TabContainer.vue -->
<template>
  <div>
    <button 
      v-for="tab in tabs" 
      :key="tab.name"
      @click="currentTab = tab.name"
    >
      {{ tab.label }}
    </button>
    
    <!-- Dynamic Components -->
    <component :is="currentTabComponent" />
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import HomeTab from './tabs/HomeTab.vue'
import ProfileTab from './tabs/ProfileTab.vue'
import SettingsTab from './tabs/SettingsTab.vue'

const tabs = [
  { name: 'home', label: 'Home' },
  { name: 'profile', label: 'Profile' },
  { name: 'settings', label: 'Settings' }
]

const currentTab = ref('home')

const currentTabComponent = computed(() => ({
  home: HomeTab,
  profile: ProfileTab,
  settings: SettingsTab
}[currentTab.value]))
</script>
▶ Experimente

(3) 5 principais cenários de aplicação

Cena Componente dinâmico
Alternar entre abas ✅
Roteiro/Diálogo ✅
Formulários com várias etapas ✅
Visualização da rota ✅ (componente interno <router-view>)
Troca de tema (layouts diferentes) ✅

4. Componentes assíncronos defineAsyncComponent

(1) Por que os componentes assíncronos são necessários?

Os componentes padrão carregam todo o código imediatamente ao import. Componentes grandes (como editores de texto rico e bibliotecas de gráficos) não são necessários para a primeira tela, mas bloqueiam o carregamento. Os componentes assíncronos são carregados sob demanda, resultando em uma primeira tela mais rápida.

VUE
<script setup>
import { defineAsyncComponent } from 'vue'
import LoadingSpinner from './LoadingSpinner.vue'

// Asynchronous Components:Only when using ChartEditor Load its code only when needed
const ChartEditor = defineAsyncComponent({
  // 1. Load Function
  loader: () => import('./ChartEditor.vue'),
  
  // 2. Display while loading
  loadingComponent: LoadingSpinner,
  
  // 3. Display when loading fails
  errorComponent: ErrorMessage,
  
  // 4. Load Delay(Prevent Flickering)
  delay: 200
})
</script>

<template>
  <ChartEditor v-if="showEditor" />
</template>

(2) Notação simplificada

VUE
<script setup>
import { defineAsyncComponent } from 'vue'

// ✅ Simplified Version:Only loader
const ChartEditor = defineAsyncComponent(() => import('./ChartEditor.vue'))
</script>

(3) 5 cenários principais para componentes assíncronos

Cenário Carregamento assíncrono
Editor de texto rico ✅
Biblioteca de gráficos (ECharts/D3) ✅
Formulários extensos (com mais de 100 campos) ✅
Janela modal ✅
Carregamento diferido de rotas ✅ (Utilizado automaticamente pelo Vue Router)

5. <Suspense> Como lidar com componentes assíncronos

(1) O que é suspense?

O Suspense é o coordenador de carregamento assíncrono de componentes do Vue 3 — ele gerencia automaticamente o carregamento e os estados de erro dos componentes assíncronos. Diga adeus à necessidade de escrever manualmente v-if="loading".

(2) 2 vagas

(3) 5 principais vantagens

Vantagem Descrição
Simplicidade Não é preciso codificar manualmente o estado de carregamento
Unificado Processamento unificado de vários componentes assíncronos
Aninhamento Suporta Suspense aninhado
Tratamento de erros Funciona com onErrorCaptured
Compatível com SSR Espera automática no lado do servidor

▶ Exemplo: Componentes assíncronos + Suspense

▶ Experimente

Saída:

TEXT
show = false → nada renderizado
Clique em Toggle → "Loading chart..."
HeavyChart carregado → gráfico com data [1..5]

6. Componentes dinâmicos + cache com keep-alive

(1) Comportamento padrão: a troca de componentes faz com que eles sejam destruídos e reconstruídos

(2) Cache Keep-Alive (para evitar a criação de duplicatas)

(3) Configurações-chave do keep-alive 3


▶ Exemplo: Componentes dinâmicos + cache com keep-alive

▶ Experimente

Saída:

TEXT
Trocar de aba → componente anterior mantido em cache
Voltar à aba → dados preservados (sem novo fetch)
:max="3" → no máximo 3 instâncias em cache

7. Exercício abrangente: abas dinâmicas com componente dinâmico

▶ Exemplo: Noções básicas sobre abas dinâmicas

VUE
<template>
  <div>
    <nav>
      <button
        v-for="tab in tabs"
        :key="tab.name"
        :class="{ active: currentTab === tab.name }"
        @click="currentTab = tab.name"
      >
        {{ tab.label }}
      </button>
    </nav>
    
    <component :is="currentTabComponent" />
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import HomeTab from './tabs/HomeTab.vue'
import ProfileTab from './tabs/ProfileTab.vue'

const tabs = [
  { name: 'home', label: 'Home' },
  { name: 'profile', label: 'Profile' },
  { name: 'settings', label: 'Settings' }
]
const currentTab = ref('home')

const currentTabComponent = computed(() => ({
  home: HomeTab,
  profile: ProfileTab,
  settings: SettingsTab
}[currentTab.value]))
</script>
▶ Experimente

Saída:

TEXT
3 botões: Home (active), Profile, Settings
Conteúdo inicial: HomeTab
Clicar em Settings → SettingsTab não foi importado (ReferenceError)

(1) 📊 4. Comparação de 5 maneiras de usar :is

Sintaxe Exemplo Uso
String <component :is="'HomeTab'"> Registro global (não recomendado)
Objeto componente <component :is="HomeTab"> Importação estática (mais comum)
Objeto de componente assíncrono <component :is="AsyncComponent"> Carregamento sob demanda
Propriedade calculada <component :is="currentTabComponent"> Comutação dinâmica
Objeto embutido <component :is="{ template: '...' }"> Cenário simples

(2) 📊 5. Referência rápida para 5 erros comuns

Erro Sintoma Solução
:é uma string, mas não está registrada globalmente Aviso: Componente desconhecido Use um objeto de componente ou registre-o primeiro
Componentes assíncronos não têm alternativa Tela em branco durante o carregamento Envolver com Suspense
Alterar componentes para recarregar os dados Baixo desempenho Usar cache keep-alive
Erros não tratados em componentes assíncronos Falhas silenciosas Use com onErrorCaptured
Esqueci de adicionar :key ao componente dinâmico Inconsistência de estado Adicionar :key="tab.name"

(3) 📊 6. 5 Principais comparações de desempenho

Modo Primeira tela Botão Aplicável
Importação direta Lenta Atualizar Widget
Importação dinâmica Rápida Lenta na primeira troca Componentes grandes
Suspense Rapidez Fluidez Prioridade à experiência do usuário
keep-alive Rápido 0 Atualização Troca frequente
Assíncrono + keep-alive ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Melhores práticas

Diretivas relacionados:v-if

❓ Perguntas Frequentes

P Qual é a diferença entre componentes dinâmicos e v-if?
R Com o v-if, mesmo que haja 5 condições e 5 ramificações, o componente ainda é carregado na íntegra. Com os componentes dinâmicos, utiliza-se uma única tag <component>, e o componente muda com base no atributo :is, tornando-o mais conciso. Os componentes assíncronos também podem ser carregados sob demanda.
P defineAsyncComponent precisa estar no nível superior de setup?
R Sim. defineAsyncComponent(() => import('...')) deve ser chamado no nível superior de <script setup> (não dentro de uma função).
P O Suspense é um recurso estável?
R Ele está estável na versão Vue 3.2 e posteriores. Você pode usá-lo com confiança, mas recomendamos testar exaustivamente o comportamento de fallback em ambientes de produção.
P Os componentes dinâmicos podem passar props?
R Sim. Use v-bind diretamente: <component :is="Comp" :prop1="x" :prop2="y" />.
P Como faço para capturar erros em componentes assíncronos?
R Use a opção errorComponent + onErrorCaptured: { loader, errorComponent: ErrorComp }. No Suspense, você pode envolver o código com onErrorCaptured.
P Os dados dos componentes armazenados em cache pelo keep-alive são persistidos?
R Os dados são mantidos (não são destruídos) enquanto estiverem no cache. No entanto, atualizar a página ou mudar de rota limpará o cache. Use o Pinia para garantir a persistência.
P Qual é a relação entre defineAsyncComponent e o carregamento diferido do Vue Router?
R O Vue Router usa internamente defineAsyncComponent para implementar o carregamento diferido das rotas. Essencialmente, trata-se da mesma coisa.

📖 Resumo


📝 Exercícios

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

    Implemente um seletor de abas simples:

    • 3 abas (Página inicial/Perfil/Configurações)
    • Use <component :is> para alternar dinamicamente
    • Saída no Switch: “Componente X criado/destruído”
  2. Problemas avançados (Dificuldade: ⭐⭐)

    Implementação da tecla Tab + carregamento assíncrono:

    • 3 guias; a guia “Configurações” é carregada de forma assíncrona usando defineAsyncComponent
    • Exibir o status de carregamento (símbolo “v” escrito à mão, se estiver carregando)
    • Não atualiza a página ao voltar para a guia “Página inicial”
  3. Problema desafiador (Dificuldade: ⭐⭐⭐)

    Implementação de um sistema completo, dinâmico, assíncrono e com cache:

    1. 5 abas, das quais pelo menos 2 são carregadas de forma assíncrona
    2. Envolva com <Suspense>
    3. <keep-alive :max="3"> Cache
    4. Saída onActivated/onDeactivated ao alternar
    5. Exibir o ErrorComponent quando um componente assíncrono falhar
    6. Medir o tempo de carregamento da primeira tela (antes e depois da implementação assíncrona)
    7. TypeScript: Componentes dinâmicos fortemente tipados
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%