Las propiedades computadas son un pilar fundamental en el ecosistema de Vue, permitiendo derivar estado de manera reactiva y eficiente. Sin embargo, la transición de la versión 2 a la 3 trajo consigo una reescritura completa del sistema de reactividad, lo que alteró significativamente cómo funcionan estas propiedades a nivel de motor.
Mecanismo Reactivo y Seguimiento de Dependencias
En la iteración anterior, el framwork se basa en Object.defineProperty para interceptar accesos y mutaciones. Las propiedades computadas utilizan un Watcher de tipo perezoso (lazy). Cuando se evalúa el getter por primera vez, el sistema utiliza una varible global (Dep.target) para registrar las dependencias. Este enfoque, aunque funcional, es propenso a recolectar dependencias innecesarias en escenarios complejos y carece de la flexibilidad para manejar estructuras de datos anidadas de forma nativa sin inicialización recursiva.
Por el contrario, la versión moderna adopta los Proxy de ECMAScript 6. La implementación de computed se construye sobre la primitiva effect. En lugar de un Watcher, se crea un efecto reactivo perezoso. El seguimiento de dependencias se gestiona mediante una pila interna de efectos, lo que garantiza una recolección precisa y elimina los problemas de dependencias fantasma o redundantes.
Ejecución Perezosa y Estrategia de Caché
Ambas versiones comparten el principio de evaluación perezosa y almacenamiento en caché: el valor solo se recalcula si sus dependencias reactivas han mutado. No obstante, la estrategia de invalidación de caché difiere en su implementación interna:
- Arquitectura antigua: Cuando una dependencia cambia, el
Watcherde la propiedad computada se marca como "dirty" (sucio). El recálculo se pospone hasta que la propiedad sea leída nuevamente en la plantilla o el script. - Arquitectura moderna: Al mutar una dependencia, se invoca un planificador (scheduler) asociado al efecto. Este planificador marca el estado interno como sucio y notifica a los efectos suscriptores, optimizando el ciclo de actualizaciones y evitando recalculaciones en cascada innecesarias durante el mismo tick del DOM.
Implementación Básica y Caché
A continuación, se ilustra el uso estándar con la API de Composición, utilizando un escenario de cálculo financiero:
import { ref, computed } from 'vue';
const precioBase = ref(100);
// El valor se almacena en caché y solo se reevalúa si precioBase cambia
const precioConImpuestos = computed(() => {
return precioBase.value * 1.21; // Aplicando un 21% de IVA
});
console.log(precioConImpuestos.value); // 121
precioBase.value = 200;
console.log(precioConImpuestos.value); // 242
Propiedades Computadas de Lectura y Escritura
Una limitación histórica era que las propiedades computadas resultantes eran estrictamente de solo lectura. La arquitectura actual introduce la capacidad de definir un setter personalizado, permitiendo la mutación inversa del estado original y facilitando el enlace bidireccional (v-model) con datos derivados.
import { ref, computed } from 'vue';
const gradosCelsius = ref(0);
const gradosFahrenheit = computed({
get: () => (gradosCelsius.value * 9/5) + 32,
set: (nuevoValorF) => {
gradosCelsius.value = (nuevoValorF - 32) * 5/9;
}
});
gradosFahrenheit.value = 212;
console.log(gradosCelsius.value); // 100
Capacidades de Depuración
El nuevo sistema basado en Proxy y effect no solo mejora el rendimiento en tiempo de ejecución, sino que tammbién facilita la instrumentación. Las herramientas de desarrollo (DevTools) pueden inspeccionar el grafo de dependencias de las propiedades computadas con granularidad, mostrando exactamente qué efectos están suscritos y por qué se ha disparado un recálculo, proporcionando una trazabilidad que era opaca en la implementación basada en defineProperty.