Skip to content

03. Reactividad

El sistema de reactividad de Vue 3 ha sido completamente reescrito utilizando las capacidades modernas de JavaScript, especialmente los Proxies de ES6. Esto permite un seguimiento de dependencias más preciso y eficiente que en Vue 2.

La función ref() crea un objeto reactivo para valores primitivos (string, number, boolean) y objetos. Envuelve el valor en un objeto con una propiedad .value.

Uso de ref()
import { ref } from 'vue'
// Para valores primitivos
const count = ref(0)
const name = ref('Vue 3')
const isActive = ref(true)
// Para objetos
const user = ref({ id: 1, name: 'John' })
// Acceso y modificación
console.log(count.value) // 0
count.value++ // 1
// Con objetos, la propiedad sigue siendo reactiva
console.log(user.value.name) // 'John'
user.value.name = 'Jane' // Reactivo
// También se puede reemplazar todo el objeto
user.value = { id: 2, name: 'Alice' } // Reactivo
  • Para valores primitivos (siempre)
  • Para objetos cuando necesitas reemplazar toda la referencia
  • Cuando necesitas pasar la referencia reactiva a funciones

La función reactive() convierte un objeto en un proxy reactivo. A diferencia de ref(), no requiere acceder a una propiedad .value, pero solo funciona con objetos y arrays.

Uso de reactive()
import { reactive } from 'vue'
// Crear un objeto reactivo
const state = reactive({
count: 0,
user: {
name: 'John',
age: 30
},
items: ['apple', 'banana']
})
// Acceso directo (sin .value)
console.log(state.count) // 0
state.count++ // 1
// Las propiedades anidadas también son reactivas
state.user.age++ // 31
state.items.push('orange') // Reactivo
  1. Solo funciona con objetos: No puede hacer reactivos valores primitivos
  2. Pierde reactividad con desestructuración:
const state = reactive({ count: 0 })
// Esto rompe la reactividad
const { count } = state
// 'count' ya no es reactivo
  1. No se puede reasignar la variable:
let state = reactive({ count: 0 })
// Esto rompe la reactividad
state = reactive({ count: 1 })
  • Para objetos complejos con muchas propiedades anidadas
  • Cuando prefieres una sintaxis más limpia sin .value
  • Cuando no necesitas reemplazar toda la referencia

La función readonly() crea una versión de solo lectura de un objeto reactivo (creado con ref() o reactive()).

Uso de readonly()
import { ref, reactive, readonly } from 'vue'
// Con ref
const original = ref({ count: 0 })
const copy = readonly(original)
// Con reactive
const state = reactive({ count: 0 })
const readonlyState = readonly(state)
// Intentar modificar genera una advertencia
copy.value.count++ // Advertencia en consola
readonlyState.count++ // Advertencia en consola
// El original sigue siendo modificable
original.value.count++ // Funciona y actualiza copy
  • Pasar datos a componentes hijos que no deben modificarlos
  • Crear una copia inmutable de un estado para prevenir modificaciones accidentales
  • Implementar patrones de flujo de datos unidireccional

Estas versiones “superficiales” de ref() y reactive() solo hacen reactivo el nivel superior del objeto, no sus propiedades anidadas.

import { shallowRef } from 'vue'
const state = shallowRef({ count: 0, user: { name: 'John' } })
// Esto es reactivo
state.value = { count: 1, user: { name: 'Jane' } }
// Esto NO es reactivo (no desencadena actualizaciones)
state.value.count++
state.value.user.name = 'Jane'
  • Para mejorar el rendimiento con objetos grandes y complejos
  • Cuando solo necesitas reactividad en el primer nivel
  • Para objetos que contienen datos que no deben ser reactivos (como bibliotecas externas)

Estas funciones ayudan a mantener la reactividad cuando necesitas desestructurar propiedades de objetos reactivos.

Crea una referencia reactiva a una propiedad específica de un objeto reactivo.

import { reactive, toRef } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
// Crear una referencia a state.count
const count = toRef(state, 'count')
// Ambas formas actualizan el estado y son reactivas
count.value++
state.count++ // Ambos son 2

Convierte un objeto reactivo en un objeto normal donde cada propiedad es una referencia reactiva.

Uso de toRefs()
import { reactive, toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
// Convertir todas las propiedades a refs
const stateRefs = toRefs(state)
// Ahora podemos desestructurar manteniendo la reactividad
const { count, name } = stateRefs
// Ambas formas actualizan el estado y son reactivas
count.value++
state.count++ // Ambos son 2

Caso de uso común: retornar estado de composables

Section titled “Caso de uso común: retornar estado de composables”
function useFeature() {
const state = reactive({
count: 0,
name: 'Feature'
})
function increment() {
state.count++
}
// Permite desestructurar manteniendo reactividad
return {
...toRefs(state),
increment
}
}
// En un componente
const { count, name, increment } = useFeature()

La función unref() extrae el valor interno de un ref, o devuelve el argumento tal cual si no es un ref.

import { ref, unref } from 'vue'
const count = ref(0)
const plainNumber = 1
console.log(unref(count)) // 0 (extrae el valor)
console.log(unref(plainNumber)) // 1 (devuelve tal cual)

Es equivalente a: isRef(val) ? val.value : val

  • Funciones que aceptan tanto refs como valores normales
  • Simplificar código que maneja diferentes tipos de entrada

Funciones de verificación: isRef(), isReactive(), isReadonly()

Section titled “Funciones de verificación: isRef(), isReactive(), isReadonly()”

Estas funciones permiten comprobar el tipo de un valor reactivo.

Funciones de verificación
import { ref, reactive, readonly, isRef, isReactive, isReadonly } from 'vue'
const num = ref(0)
const obj = reactive({count: 0})
const readonlyObj = readonly(obj)
const plainObj = { count: 0 }
// Verificaciones
console.log(isRef(num)) // true
console.log(isRef(plainObj)) // false
console.log(isReactive(obj)) // true
console.log(isReactive(num)) // false
console.log(isReactive(num.value)) // false
console.log(isReactive(plainObj)) // false
console.log(isReadonly(readonlyObj)) // true
console.log(isReadonly(obj)) // false
  • Funciones que necesitan comportarse de manera diferente según el tipo de entrada
  • Depuración y verificación de tipos
  • Implementación de lógica condicional basada en el tipo de reactividad
APITipo de valorRequiere .valueReactividad anidadaUso principal
ref()CualquieraValores primitivos y objetos que necesitan ser reemplazados
reactive()Solo objetosNoObjetos complejos con propiedades anidadas
readonly()Refs u objetosDepende del origenPrevenir modificaciones
shallowRef()CualquieraNoMejora de rendimiento, objetos grandes
shallowReactive()Solo objetosNoNoMejora de rendimiento, objetos grandes
toRef()Propiedad de objetoMantener reactividad de una propiedad específica
toRefs()ObjetoDesestructurar manteniendo reactividad
🐝