Programación Reactiva: Conceptos y Ejemplo Práctico en JavaScript

La programación reactiva es un paradigma declarativo basado en flujos de datos y la propagación de cambios. Para ilustrar su funcionamineto básico, consideremos un ejemplo simple donde las actualizaciones de variables no se reflejan automáticamente en los cálculos dependientes.

let precio = 5
let cantidad = 2
let resultado = precio * cantidad // Calcula el valor inicial: 10
precio = 20 // Actualizamos el precio
console.log(`Resultado: ${resultado}`) // Muestra 10, no se actualiza automáticamente
// El objetivo es que 'resultado' se convierta en 40 tras cambiar el precio

Para lograr que los cálculos se recalculen cuando cambian los datos, necesitamos almacenar la función de cálculo y ejecutarla en respuesta a las actualizaciones. Primero, definimos una función de registro y una de ejecución:

let precio = 5
let cantidad = 2
let resultado = 0
let objetivo = null
let almacen = []

objetivo = () => { resultado = precio * cantidad }

function registrar() {
  almacen.push(objetivo)
}

function ejecutar() {
  almacen.forEach(fn => fn())
}

registrar()
objetivo() // Ejecuta el cálculo inicial

precio = 20
console.log(resultado) // Muestra 10
ejecutar() // Recalcula
console.log(resultado) // Ahora muestra 40

Para mayor robustez, encapsulamos este comportamiento en una clase que implemente el patrón observador. Esto permite gestionar múltiples dependencias de manera estructurada.

class Dependencia {
  constructor() {
    this.observadores = []
  }

  suscribir() {
    if (objetivo && !this.observadores.includes(objetivo)) {
      this.observadores.push(objetivo)
    }
  }

  notificar() {
    this.observadores.forEach(obs => obs())
  }
}

Con esta clase, simplificamos el proceso mediante una función observadora que configura la dependencia y ejecuta el cálculo:

function observar(funcionCalculo) {
  objetivo = funcionCalculo
  dep.suscribir()
  objetivo()
  objetivo = null
}

const dep = new Dependencia()
let precio = 5
let cantidad = 2
let total = 0

observar(() => {
  total = precio * cantidad
})

console.log(total) // 10
precio = 20
console.log(total) // 10, aún no se actualiza
dep.notificar()
console.log(total) // 40, se actualiza tras notificar

Para aplicar la reactividad a múltiples propiedades de un objeto, usamos Object.defineProperty para interceptar accesos y modificaciones, vinculando cada propiedad a su propia instancia de dependencia.

let datos = { precio: 5, cantidad: 2 }
let objetivo = null

Object.keys(datos).forEach(clave => {
  let valorInterno = datos[clave]
  const dep = new Dependencia()

  Object.defineProperty(datos, clave, {
    get() {
      dep.suscribir()
      return valorInterno
    },
    set(nuevoValor) {
      valorInterno = nuevoValor
      dep.notificar()
    }
  })
})

function observar(funcionCalculo) {
  objetivo = funcionCalculo
  objetivo()
  objetivo = null
}

let total = 0
observar(() => {
  total = datos.precio * datos.cantidad
})

console.log(total) // 10
datos.precio = 20 // Dispara el setter y notifica
console.log(total) // 40
datos.cantidad = 3 // Dispara el setter y notifica
console.log(total) // 60

Este enfoque es fundamental en frameworks como Vue.js, donde cada propeidad reactiva tiene getter/setter que gestionan dependencias. Los componentes poseen observadores que se registran durante el cálculo y se actualizan cuando cambian los datos.

Etiquetas: programación reactiva JavaScript vue.js patrón observador Object.defineProperty

Publicado el 7-3 05:53