vuejs-watch-watch-effect

Qué son y cómo usar Watch y WatchEffect en Vue.js

  • 5 min

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 watchy 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, un reactive, un computed, 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 el callback inmediatamente después de crear el watch, 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ísticawatchwatchEffect
DependenciasSe especifican explícitamenteSe detectan automáticamente
Uso típicoPara observar cambios específicosPara efectos secundarios
Acceso a valoresNuevo y antiguo valorSolo el nuevo valor
ConfiguraciónMás configurableMenos 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.