En Vue.js, un watcher es una función que observa un dato reactivo y se ejecuta cada vez que ese dato cambia.
A diferencia de las computed properties, que devuelven un valor calculado, los watchers se utilizan para realizar efectos secundarios (como hacer llamadas a una API, actualizar el DOM o ejecutar lógica compleja).
Es decir, los watchers son como funciones listeners reactivas, que nos permiten observar cambios en una propiedad o dato y ejecutar una acción cuando se detectan cambios.
Para ello disponemos de las funciones watch
y watchEffect
que nos permite observar cambios una o varias propiedades reactivas y ejecutar una función cuando las propiedades cambian.
Creación de watchers con watch
La función principal para crear watchers en Vue.Js es la función watch
, que tiene la siguiente sintaxis básica,
watch(fuente, callback, opciones);
- fuente: La propiedad reactiva que queremos observar. Puede ser un
ref
, unreactive
, uncomputed
, o incluso una función que devuelve un valor. - callback: La función que se ejecutará cuando la fuente cambie. Recibe dos parámetros: el nuevo valor y el valor anterior.
- opciones (opcional): Un objeto de configuración que permite personalizar el comportamiento de
watch
.
Vamos a verlo con un ejemplo. Supongamos que tenemos una propiedad reactiva count
y queremos ejecutar una función cada vez que count
cambie:
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`El valor de count ha cambiado de ${oldValue} a ${newValue}`);
});
return {
count,
};
},
};
En este ejemplo, cada vez que count
cambie, se imprimirá en la consola el nuevo valor y el valor anterior.
Observar múltiples fuentes con watch
watch
también nos permite observar múltiples fuentes simultáneamente. Para ello, pasamos un array de fuentes como primer argumento.
import { ref, watch } from 'vue';
export default {
setup() {
const firstName = ref('Juan');
const lastName = ref('Pérez');
watch([firstName, lastName], ([newFirstName, newLastName], [oldFirstName, oldLastName]) => {
console.log(`Nombre completo cambiado de ${oldFirstName} ${oldLastName} a ${newFirstName} ${newLastName}`);
});
return {
firstName,
lastName,
};
},
};
En este caso, el callback
se ejecutará cada vez que firstName
o lastName
cambien.
Opciones de watch
La función watch
acepta un tercer parámetro opcional que permite configurar su comportamiento. Algunas de las opciones más comunes son:
immediate
: Ejecuta elcallback
inmediatamente después de crear elwatch
, incluso si la fuente no ha cambiado.deep
: Observa cambios profundos en objetos o arrays anidados.
Por defecto, un watcher solo se ejecuta cuando el valor observado cambia. Sin embargo, si deseas que el watcher se ejecute inmediatamente al momento de crearse, puedes habilitar la opción immediate.
Supongamos que tenemos una propiedad mensaje
y queremos que se imprima inmediatamente cuando se carga el componente, además de reaccionar a cualquier cambio posterior.
<template>
<div>
<p>{{ mensaje }}</p>
<button @click="cambiarMensaje">Cambiar mensaje</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
const mensaje = ref('Hola, mundo!');
// Watcher para observar cambios en el mensaje
watch(mensaje, (nuevoValor, viejoValor) => {
console.log('El mensaje cambió:', nuevoValor);
}, { immediate: true });
function cambiarMensaje() {
mensaje.value = '¡Nuevo mensaje!';
}
</script>
En este ejemplo, el watcher con la opción immediate: true
se ejecuta inmediatamente al inicio, mostrando el valor inicial del mensaje. Además, se sigue observando cualquier cambio posterior en el valor de mensaje
.
Por defecto, los watchers solo observan cambios en el valor primitivo de una referencia reactiva. Sin embargo, si el dato observado es un objeto o un array, puedes habilitar la observación profunda para detectar cambios en las propiedades internas.
Supongamos que tenemos un objeto usuario
y queremos reaccionar a cambios en sus propiedades.
<template>
<div>
<p>Nombre: {{ usuario.nombre }}</p>
<p>Edad: {{ usuario.edad }}</p>
<button @click="cambiarNombre">Cambiar nombre</button>
<button @click="cambiarEdad">Cambiar edad</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
const usuario = ref({
nombre: 'Juan',
edad: 30,
});
// Watcher para observar cambios en el objeto usuario
watch(usuario, (nuevoValor, viejoValor) => {
console.log('El usuario cambió:', nuevoValor);
}, { deep: true });
function cambiarNombre() {
usuario.value.nombre = 'Carlos';
}
function cambiarEdad() {
usuario.value.edad++;
}
</script>
En este ejemplo, el watcher observa cambios en el objeto usuario
. Como el objeto es complejo, habilitamos la observación profunda (deep: true
) para detectar cambios en sus propiedades internas.
Creación de watchers con watchEffect
La otra alternativa para crear watchers es la función watchEffect
. Es muy similar función similar a watch
, pero con la diferencia de que automáticamente rastrea todas las dependencias que se utilizan dentro de su callback
.
Es decir, que no necesitamos especificar explícitamente qué propiedades observar. Vamos a ver un resumen de sus diferencias,
Característica | watch | watchEffect |
---|---|---|
Dependencias | Se especifican explícitamente | Se detectan automáticamente |
Uso típico | Para observar cambios específicos | Para efectos secundarios |
Acceso a valores | Nuevo y antiguo valor | Solo el nuevo valor |
Configuración | Más configurable | Menos configurable |
La sintaxis de watchEffect
es la siguiente
watchEffect(callback);
- callback: La función que se ejecutará cada vez que alguna de sus dependencias reactivas cambie.
Vamos a verlo con un ejemplo,
import { ref, watchEffect } from 'vue';
export default {
setup() {
const count = ref(0);
watchEffect(() => {
console.log(`El valor de count es ${count.value}`);
});
return {
count,
};
},
};
En este ejemplo, watchEffect
automáticamente rastrea count
y ejecuta el callback
cada vez que count
cambia.