[Medium] watch vs watchEffect
1. What are watch and watchEffect?
O que são watch e watchEffect?
watch e watchEffect são duas APIs da Composition API do Vue 3 usadas para observar mudanças em dados reativos.
watch
Definição: Específica explicitamente a fonte de dados a ser observada, executando uma função callback quando os dados mudam.
<script setup>
import { ref, watch } from 'vue';
const count = ref(0);
const message = ref('Hello');
// Observar uma única fonte de dados
watch(count, (newValue, oldValue) => {
console.log(`count mudou de ${oldValue} para ${newValue}`);
});
// Observar múltiplas fontes de dados
watch([count, message], ([newCount, newMessage], [oldCount, oldMessage]) => {
console.log('count ou message mudou');
});
</script>
watchEffect
Definição: Rastreia automaticamente os dados reativos usados na função callback, executando automaticamente quando esses dados mudam.
<script setup>
import { ref, watchEffect } from 'vue';
const count = ref(0);
const message = ref('Hello');
// Rastreia automaticamente count é message
watchEffect(() => {
console.log(`count: ${count.value}, message: ${message.value}`);
// Quando count ou message muda, executa automaticamente
});
</script>
2. watch vs watchEffect: Key Differences
Principais diferenças entre watch e watchEffect
1. Específicacao da Fonte de Dados
watch: Específica explicitamente os dados a observar
const count = ref(0);
const message = ref('Hello');
// Específica explicitamente observar count
watch(count, (newVal, oldVal) => {
console.log('count mudou');
});
// Específica explicitamente observar múltiplos dados
watch([count, message], ([newCount, newMessage]) => {
console.log('count ou message mudou');
});
watchEffect: Rastreia automaticamente os dados usados
const count = ref(0);
const message = ref('Hello');
// Rastreia automaticamente count é message (pois são usados no callback)
watchEffect(() => {
console.log(count.value); // Rastreia count automaticamente
console.log(message.value); // Rastreia message automaticamente
});
2. Momento de Execução
watch: Execução lazy por padrão, executa apenas quando os dados mudam
const count = ref(0);
watch(count, (newVal) => {
console.log('Executou'); // Executa apenas quando count muda
});
count.value = 1; // Dispara execução
watchEffect: Executa imediatamente, depois rastreia mudanças
const count = ref(0);
watchEffect(() => {
console.log('Executou'); // Executa imediatamente uma vez
console.log(count.value);
});
count.value = 1; // Executa novamente
3. Acesso ao Valor Antigo
watch: Pode acessar o valor antigo
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`Mudou de ${oldVal} para ${newVal}`);
});
watchEffect: Não pode acessar o valor antigo
const count = ref(0);
watchEffect(() => {
console.log(count.value); // só pode acessar o valor atual
// Não é possível obter o valor antigo
});
4. Parar de Observar
watch: Retorna função de parada
const count = ref(0);
const stopWatch = watch(count, (newVal) => {
console.log(newVal);
});
// Parar de observar
stopWatch();
watchEffect: Retorna função de parada
const count = ref(0);
const stopEffect = watchEffect(() => {
console.log(count.value);
});
// Parar de observar
stopEffect();
3. When to Use watch vs watchEffect?
Quando usar watch? Quando usar watchEffect?
Quando Usar watch
-
Necessidade de especificar explicitamente os dados a observar
watch(userId, (newId) => {
fetchUser(newId);
}); -
Necessidade de acessar o valor antigo
watch(count, (newVal, oldVal) => {
console.log(`Mudou de ${oldVal} para ${newVal}`);
}); -
Necessidade de execução lazy (apenas quando muda)
watch(searchQuery, (newQuery) => {
if (newQuery.length > 2) {
search(newQuery);
}
}); -
Necessidade de controle mais fino
watch(
() => user.value.id,
(newId) => {
fetchUser(newId);
},
{ immediate: true, deep: true }
);
Quando Usar watchEffect
-
Rastreamento automático de múltiplos dados relacionados
watchEffect(() => {
// Rastreia automaticamente todos os dados reativos usados
if (user.value && permissions.value.includes('admin')) {
loadAdminData();
}
}); -
Não necessita do valor antigo
watchEffect(() => {
console.log(`Contagem atual: ${count.value}`);
}); -
Necessidade de execução imediata
watchEffect(() => {
// Executa imediatamente, depois rastreia mudanças
updateChart(count.value, message.value);
});
4. Common Interview Questions
Perguntas Comuns de Entrevista
Pergunta 1: Diferença Básica
Explique a ordem de execução e resultado do seguinte código.
const count = ref(0);
const message = ref('Hello');
// watch
watch(count, (newVal) => {
console.log('watch:', newVal);
});
// watchEffect
watchEffect(() => {
console.log('watchEffect:', count.value, message.value);
});
count.value = 1;
message.value = 'World';
Clique para ver a resposta
const count = ref(0);
const message = ref('Hello');
// watch: execução lazy, não executa imediatamente
watch(count, (newVal) => {
console.log('watch:', newVal);
});
// watchEffect: executa imediatamente
watchEffect(() => {
console.log('watchEffect:', count.value, message.value);
// Saída imediata: watchEffect: 0 Hello
});
count.value = 1;
// Dispara watch: watch: 1
// Dispara watchEffect: watchEffect: 1 Hello
message.value = 'World';
// watch não observa message, não executa
// watchEffect observa message, executa: watchEffect: 1 World
Ordem de saída:
watchEffect: 0 Hello(execução imediata)watch: 1(count mudou)watchEffect: 1 Hello(count mudou)watchEffect: 1 World(message mudou)
Diferenças-chave:
watchexecução lazy, executa apenas quando os dados observados mudamwatchEffectexecuta imediatamente, depois rastreia todos os dados usados
Pergunta 2: Acesso ao Valor Antigo
Explique como obter o valor antigo ao usar watchEffect.
Clique para ver a resposta
Problema: watchEffect não pode acessar o valor antigo diretamente
const count = ref(0);
watchEffect(() => {
console.log(count.value); // só pode acessar o valor atual
// Não é possível obter o valor antigo
});
Solução 1: Usar ref para armazenar o valor antigo
const count = ref(0);
const prevCount = ref(0);
watchEffect(() => {
console.log(`Mudou de ${prevCount.value} para ${count.value}`);
prevCount.value = count.value; // Atualizar valor antigo
});
Solução 2: Usar watch (se precisar do valor antigo)
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`Mudou de ${oldVal} para ${newVal}`);
});
Recomendação:
- Se precisar do valor antigo, prefira usar
watch watchEffecté adequado para cenários que não necessitam do valor antigo
Pergunta 3: Escolher watch ou watchEffect?
Explique qual deve ser usado nós seguintes cenários: watch ou watchEffect.
// Cenário 1: Observar mudança de ID do usuario, recarregar dados
const userId = ref(1);
// ?
// Cenário 2: Quando validação do formulário passa, habilitar botão de envio automaticamente
const form = reactive({ username: '', password: '' });
const isValid = computed(() => form.username && form.password);
// ?
// Cenário 3: Observar palavra-chave de busca, executar busca (com debounce)
const searchQuery = ref('');
// ?
Clique para ver a resposta
Cenário 1: Observar ID do Usuario
const userId = ref(1);
// ✅ Usar watch: específica explicitamente os dados a observar
watch(userId, (newId) => {
fetchUser(newId);
});
Cenário 2: Validação de Formulário
const form = reactive({ username: '', password: '' });
const isValid = computed(() => form.username && form.password);
// ✅ Usar watchEffect: rastreia automaticamente dados relacionados
watchEffect(() => {
submitButton.disabled = !isValid.value;
});
Cenário 3: Busca (com debounce)
const searchQuery = ref('');
// ✅ Usar watch: necessita controle mais fino (debounce)
let timeoutId;
watch(searchQuery, (newQuery) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
search(newQuery);
}, 300);
});
Princípios de escolha:
- Especificar explicitamente dados a observar →
watch - Rastrear automaticamente múltiplos dados relacionados →
watchEffect - Necessita valor antigo ou controle fino →
watch - Necessita execução imediata →
watchEffect
5. Best Practices
Melhores Práticas
Práticas Recomendadas
// 1. Usar watch ao especificar explicitamente dados a observar
watch(userId, (newId) => {
fetchUser(newId);
});
// 2. Usar watchEffect ao rastrear automaticamente múltiplos dados relacionados
watchEffect(() => {
if (user.value && permissions.value.includes('admin')) {
loadAdminData();
}
});
// 3. Usar watch quando precisar do valor antigo
watch(count, (newVal, oldVal) => {
console.log(`Mudou de ${oldVal} para ${newVal}`);
});
// 4. Lembrar de limpar observadores
onUnmounted(() => {
stopWatch();
stopEffect();
});
Práticas a Evitar
// 1. Não realizar operações assíncronas no watchEffect sem tratar limpeza
watchEffect(async () => {
const data = await fetchData(); // ❌ Pode causar vazamento de memória
// ...
});
// 2. Não usar watchEffect excessivamente
// Se só precisa observar dados específicos, watch é mais explícito
watchEffect(() => {
console.log(count.value); // ⚠️ Se só precisa observar count, watch é mais adequado
});
// 3. Não modificar dados observados no watchEffect (pode causar loop infinito)
watchEffect(() => {
count.value++; // ❌ Pode causar loop infinito
});
6. Interview Summary
Resumo para Entrevista
Memorização Rápida
watch:
- Específica explicitamente dados a observar
- Execução lazy (padrão)
- Pode acessar valor antigo
- Adequado para cenários que necessitam controle fino
watchEffect:
- Rastreia automaticamente dados usados
- Executa imediatamente
- Não pode acessar valor antigo
- Adequado para rastrear automaticamente múltiplos dados relacionados
Princípios de escolha:
- Especificar observação explicitamente →
watch - Rastreamento automático →
watchEffect - Necessita valor antigo →
watch - Necessita execução imediata →
watchEffect
Exemplo de Resposta para Entrevista
P: Qual é a diferença entre watch e watchEffect?
"watch e watchEffect são ambas APIs do Vue 3 para observar mudanças em dados reativos. As principais diferenças incluem: 1) Fonte de dados: watch necessita especificar explicitamente os dados a observar, watchEffect rastreia automaticamente dados reativos usados no callback; 2) Momento de execução: watch executa lazy por padrão, apenas quando os dados mudam, watchEffect executa imediatamente e depois rastreia mudanças; 3) Acesso ao valor antigo: watch pode acessar o valor antigo, watchEffect não; 4) Cenários de uso: watch é adequado para cenários que necessitam especificar dados ou valor antigo, watchEffect é adequado para rastrear automaticamente múltiplos dados relacionados."
P: Quando usar watch? Quando usar watchEffect?
"Usar watch quando: 1) Necessita especificar explicitamente dados a observar; 2) Necessita acessar valor antigo; 3) Necessita execução lazy; 4) Necessita controle mais fino (como opções immediate, deep). Usar watchEffect quando: 1) Rastrear automaticamente múltiplos dados relacionados; 2) Não necessita valor antigo; 3) Necessita execução imediata. Em geral, se só precisa observar dados específicos, watch é mais explícito; se precisa rastrear automaticamente múltiplos dados, watchEffect é mais conveniente."