Skip to content
← Todas las preguntas
🔥 Avanzado

¿Cuándo usar el hook updated y cuáles son sus implicaciones de rendimiento?

⚡ Rendimiento⚛️ Reactividad👁️ Watchers

El hook updated (onUpdated en Composition API) se ejecuta después de cada cambio de estado reactivo que provoca un re-render. Se dispara ante CUALQUIER cambio de estado en el componente, no solo ante el que te interesa. Esto lo convierte en un lugar peligroso para operaciones costosas, llamadas a APIs o mutaciones de estado. Para la mayoría de los casos, watch o computed son una mejor opción.

Cómo funciona updated ​

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

const name = ref('Alice')
const count = ref(0)

onUpdated(() => {
  console.log('Component re-rendered')
  // Se dispara cuando name O count cambian
  // No sabes cuál lo provocó
})
</script>
Open in Vue Playground

El hook no tiene información sobre qué cambió. Solo indica que el DOM fue actualizado. Si el componente tiene 10 propiedades reactivas, el hook se dispara cuando cualquiera de ellas cambia.

Los peligros ​

Bucles infinitos por mutación de estado ​

js
// MAL: mutar estado dentro de updated dispara otra actualización
export default {
  data() {
    return { renderCount: 0 }
  },
  updated() {
    this.renderCount++ // dispara re-render → updated → renderCount++ → ...
  }
}

Los cambios de estado dentro de updated provocan otro render, que llama a updated de nuevo. El navegador se bloquea.

Llamadas a la API en cada render ​

js
// MAL: se dispara en cada re-render, no solo cuando items cambia
export default {
  data() {
    return { items: [], searchQuery: '' }
  },
  updated() {
    fetch('/api/sync', {
      method: 'POST',
      body: JSON.stringify(this.items)
    })
  }
}

Escribir en el campo de búsqueda dispara un re-render, que dispara updated, que envía una llamada a la API. Cada pulsación de teclado llega al servidor, aunque items no haya cambiado.

Datos derivados en updated ​

js
// MAL: provoca otro ciclo de actualización
export default {
  data() {
    return { numbers: [1, 2, 3, 4, 5] }
  },
  updated() {
    this.sum = this.numbers.reduce((a, b) => a + b, 0)
  }
}

Asignar this.sum dispara un re-render, que dispara updated de nuevo. Aunque no entre en un bucle infinito (porque el valor se estabiliza), genera un ciclo de render innecesario adicional.

Usar watch en su lugar ​

Los watchers son específicos. Solo se disparan cuando cambian los datos concretos que observan:

vue
<script setup>
import { ref, watch } from 'vue'
import { useDebounceFn } from '@vueuse/core'

const items = ref([])

const syncToServer = useDebounceFn((newItems) => {
  fetch('/api/sync', { method: 'POST', body: JSON.stringify(newItems) })
}, 500)

watch(
  items,
  (newItems) => {
    syncToServer(newItems)
  },
  { deep: true }
)
</script>
Open in Vue Playground

Esto solo se dispara cuando items cambia, no cuando cualquier otro estado del componente cambia. El debounce evita saturar el servidor.

Usar computed para datos derivados ​

js
// BIEN: computed cachea y realiza el seguimiento automáticamente
export default {
  data() {
    return { numbers: [1, 2, 3, 4, 5] }
  },
  computed: {
    sum() {
      return this.numbers.reduce((a, b) => a + b, 0)
    }
  }
}

Sin ciclo de render adicional. El valor se actualiza en el mismo paso de render.

Casos de uso válidos para updated ​

El hook es apropiado para sincronización DOM de bajo nivel que depende del output renderizado, no de datos específicos:

Sincronizar una librería de terceros con el DOM ​

vue
<script setup>
import { onUpdated } from 'vue'

onUpdated(() => {
  thirdPartyWidget.refresh()
})
</script>
Open in Vue Playground

Algunas librerías (renderizadores de gráficos, resaltadores de sintaxis) necesitan saber cuándo cambió el DOM para volver a medir o redibujar.

Auto-scroll tras cambios de contenido ​

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

const chatContainer = (ref < HTMLElement) | (null > null)

onUpdated(() => {
  if (chatContainer.value) {
    chatContainer.value.scrollTop = chatContainer.value.scrollHeight
  }
})
</script>

<template>
  <div ref="chatContainer" class="chat">
    <div v-for="msg in messages" :key="msg.id">{{ msg.text }}</div>
  </div>
</template>
Open in Vue Playground

La posición del scroll depende de la altura del DOM renderizado, no directamente de los datos. Este es uno de los pocos casos donde updated tiene sentido.

Con una condición de guarda ​

Si hay que usar updated, añadir una condición para evitar trabajo innecesario:

js
export default {
  data() {
    return { content: '', lastSynced: '' }
  },
  updated() {
    if (this.content !== this.lastSynced) {
      this.syncContent()
      this.lastSynced = this.content
    }
  }
}

La guarda evita que la operación se ejecute cuando un cambio de estado no relacionado provocó el re-render.

Cuándo usar cada opción ​

NecesidadUsar
Reaccionar a un cambio de dato específicowatch / watchEffect
Derivar un valor del estado reactivocomputed
Sincronizar librería de terceros tras actualización del DOMonUpdated
Hacer scroll o medir el DOM tras el renderonUpdated
Llamadas a API cuando cambian datoswatch con debounce
Actualizar estado derivadocomputed (nunca updated)

Ver también: ¿Cómo agrupa Vue las actualizaciones del DOM? · ¿Qué es nextTick y cuándo lo necesitas?

Referencias ​

Publicado bajo la licencia MIT.