💻 Exemplos: Capítulo 02: Reatividade Básica: ref(), reactive(), toRefs() e Desestruturação
Especialização em Front-End com Vue • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 02 — Gestão Segura de Reatividade com ref(), reactive() e toRefs()
O exemplo a seguir ilustra a diferença prática entre ref e reactive, o problema da perda de reatividade na desestruturação de objetos reativos e como resolvê-lo com toRefs() e toRef().
<!-- src/components/ReactivityLab.vue -->
<script setup lang="ts">
import { ref, reactive, toRefs, shallowRef } from 'vue';
// 1. Ref simples para valores primitivos ou objetos atômicos
const counter = ref<number>(0);
// 2. Objeto complexo gerenciado por Proxy via reactive()
interface UserSession {
username: string;
role: 'admin' | 'editor' | 'viewer';
loginCount: number;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
}
const session = reactive<UserSession>({
username: 'carlos.silva',
role: 'editor',
loginCount: 14,
preferences: {
theme: 'dark',
notifications: true
}
});
// 3. Desestruturação SEGURA: preserva reatividade convertendo propriedades em Refs
const { username, role, loginCount } = toRefs(session);
// 4. shallowRef para payloads gigantescos que não precisam de deep reactivity
const heavyDataset = shallowRef<number[]>([10, 20, 30, 40]);
function incrementCounter(): void {
counter.value++;
}
function updateSession(): void {
// Alteração direta reflete nas variáveis desestruturadas
session.loginCount++;
session.preferences.theme = session.preferences.theme === 'dark' ? 'light' : 'dark';
}
function promoteToAdmin(): void {
// Alterando diretamente a ref extraída via toRefs
role.value = 'admin';
}
function replaceHeavyData(): void {
// shallowRef só reage à atribuição de uma nova referência
heavyDataset.value = [...heavyDataset.value, Math.floor(Math.random() * 100)];
}
</script>
<template>
<div class="p-6 max-w-xl mx-auto bg-slate-50 border rounded-2xl shadow-sm space-y-6">
<h2 class="text-xl font-bold text-slate-800 border-b pb-2">
🧪 Laboratório de Reatividade Vue 3
</h2>
<!-- Seção 1: Ref Simples -->
<div class="bg-white p-4 rounded-xl border">
<h3 class="font-semibold text-slate-700">1. Ref Primitivo</h3>
<p class="text-sm text-slate-500 mt-1">Valor: <strong class="text-indigo-600">{{ counter }}</strong></p>
<button
@click="incrementCounter"
class="mt-2 px-3 py-1.5 text-xs font-semibold bg-indigo-50 text-indigo-700 rounded-md hover:bg-indigo-100"
>
Incrementar Ref (+1)
</button>
</div>
<!-- Seção 2: Reactive & toRefs -->
<div class="bg-white p-4 rounded-xl border space-y-2">
<h3 class="font-semibold text-slate-700">2. Estado Reativo com toRefs()</h3>
<div class="text-sm text-slate-600 space-y-1">
<p>Usuário: <code class="font-mono bg-slate-100 px-1 py-0.5 rounded">{{ username }}</code></p>
<p>Perfil: <span class="font-bold text-amber-600 uppercase">{{ role }}</span></p>
<p>Acessos: <strong>{{ loginCount }}</strong></p>
<p>Tema: <span class="capitalize">{{ session.preferences.theme }}</span></p>
</div>
<div class="flex gap-2 pt-2">
<button
@click="updateSession"
class="px-3 py-1.5 text-xs font-semibold bg-emerald-50 text-emerald-700 rounded-md hover:bg-emerald-100"
>
Registrar Acesso e Alternar Tema
</button>
<button
@click="promoteToAdmin"
class="px-3 py-1.5 text-xs font-semibold bg-amber-50 text-amber-700 rounded-md hover:bg-amber-100"
>
Promover para Admin
</button>
</div>
</div>
<!-- Seção 3: shallowRef -->
<div class="bg-white p-4 rounded-xl border">
<h3 class="font-semibold text-slate-700">3. shallowRef (Desempenho)</h3>
<p class="text-sm text-slate-500 mt-1">Total de Itens: <strong>{{ heavyDataset.length }}</strong></p>
<p class="text-xs font-mono text-slate-400 truncate mt-1">Valores: {{ heavyDataset.join(', ') }}</p>
<button
@click="replaceHeavyData"
class="mt-2 px-3 py-1.5 text-xs font-semibold bg-slate-100 text-slate-700 rounded-md hover:bg-slate-200"
>
Substituir Referência do Array
</button>
</div>
</div>
</template>
🖥️ Saída / Comportamento Esperado
Renderização Inicial:
Counter: 0
Usuário: carlos.silva | Perfil: EDITOR | Acessos: 14 | Tema: dark
Itens do Array shallowRef: 4 itens [10, 20, 30, 40]
Ações do Usuário:
1. Clicar em "Incrementar Ref":
Counter atualiza de 0 para 1 instantaneamente.
2. Clicar em "Registrar Acesso e Alternar Tema":
loginCount passa para 15 (sincronizado tanto em session.loginCount quanto na ref desestruturada loginCount).
Tema alterna de 'dark' para 'light'.
3. Clicar em "Promover para Admin":
Role passa de 'editor' para 'admin' reativamente.
4. Clicar em "Substituir Referência do Array":
Array expande para 5 elementos, disparando renderização de heavyDataset.length.
🔍 Destaques da Implementação
- Evitando Quebra de Reatividade: A instrução
const { username, role, loginCount } = toRefs(session)cria refs ligadas ao objeto original sem copiar valores estáticos primitivos. Proxydo ES6: Oreactive()intercepta operações get/set de propriedades aninhadas, ao contrário doObject.definePropertydo Vue 2 que não detectava adição/deleção de chaves.shallowRefpara Grande Volume: Evita a conversão recursiva de arrays de 10.000+ itens em proxies, economizando memória e ciclos de CPU.