Skip to content
En esta página

Reactividad en JavaScript

¿Qué es la reactividad?

Supongamos que queremos sumar dos números, a y b:

js
let a = 1
let b = 2
let total = a + b
console.log(total) // 3

Pero, ¿qué pasa si queremos que cada vez que a o b cambian de valor el total se actualice automáticamente?

js
let a = 1
let b = 2
let total = a + b
b = 9
console.log(total) // Sigue dando 3 ☹️

Podríamos usar una función:

js
let a = 1
let b = 2
const suma = (num1, num2) => num1 + num2
let total = suma(a, b)

console.log(total) // 3 👍️

b = 9
total = suma(a, b)

console.log(total) // 10 👍️

Esto funciona, pero no es realmente lo que queríamos hacer, porque cada vez que el valor de a o b cambia hay que ejecutar la función suma(a, b). Si no la ejecutamos el total no cambia. Pero la idea era que la variable total se actualice automáticamente ante cualquier cambio.

Esta actualización automática de los valores es lo que se suele llamar reactividad.

El ejemplo anterior no es un código reactivo, es imperativo. En vez de automatizar los procesos estamos indicando paso por paso lo que el programa debe hacer.

Un buen ejemplo de reactividad son las tablas de Excel:

ABC
1
2
3Total:0

Si ingresamos un número en las celdas B1 o B2 el total se actualiza automáticamente.

Esta tabla está hecha con Vue.js, no es realmente Excel, y funciona gracias a que Vue es un framework reactivo.

Pero, ¿cómo hace Vue para generar reactividad?

Reactividad en Vue.js

En el contexto del desarrollo web el término reactividad tiene un significado específico: es la sincronización automática entre la Vista y el Modelo 🤔️

La Vista es simplemente lo que vemos en la pantalla, y el Modelo son los datos (variables, objetos, arrays), de manera que cuando algún dato cambia, vemos el cambio actualizado automáticamente.

Lo que hace Vue es interceptar los cambios que se producen dentro del método data:

js
const { createApp } = Vue

createApp({

  data: () => ({
    a: 0,
    b: 0
  }),

  computed: {
    total() {
      return this.a + this.b
    }
  }

}).mount('#app')

Cuando this.a o this.b cambian la propiedad computada total también cambia, y este cambio se ve reflejado en la vista automáticamente.

De ahí viene el nombre de Vue, es una referencia al paradigma Model-View-ViewModel. Les recomiendo que lean el artículo de Wikipedia que lo explica, es muy corto.

¿Y cómo hace Vue para interceptar los cambios en data? Usando un método bastante extraño de JavaScript llamado Object.defineProperty().

Lo que hace este método es cambiar el funcionamiento normal del prototipo de Objeto 🤔️

Sí, suena raro, pero no se preocupen, ya se va a entender más adelante.

Básicamente, de lo que se trata es de hacer que, cuando una propiedad del objeto data cambia, que se se ejecute una función que actualice la vista:

js
Object.defineProperty(data, prop, {
  get () {
    return value
  },
  set (newValue) {
    value = newValue
    updateView(value)
  }
})

Esto es lo que usa Vue internamente, no es necesario que lo hagamos nosotros mismos, lo único que tenemos que hacer es declarar el objeto data y Vue se encarga del resto.

En realidad el código interno de Vue es un bastante más complejo que este ejemplo de Object.defineProperty() (acá lo pueden ver) pero básicamente funciona así (para ser más exactos, Vue 2 funciona así, Vue 3 es un poco distinto, usa algo parecido llamado objeto Proxy).

Reactividad en React.js

La reactividad en React es generada mediante métodos que al ser ejecutados producen nuevos renderizados del componente (incluyendo sus componentes hijos):

js
import React, { useState } from 'react'

const Counter = () => {
  const [count, setCount] = useState(0)

  return (
    <div>
      <button 
        onClick={() => setCount(count - 1)}
      >-</button>
      <span>{count}</span>
      <button 
        onClick={() => setCount(count + 1)}
      >+</button>
    </div>
  )
}

export default Counter

Es decir, React usa un método (en este caso, setCount) que al ejecutarse produce un cambio en la vista (en realidad, el proceso de renderizado en React es más complejo que esto, estoy simplificando).

En esto se parece bastante al ejemplo de código imperativo con la función suma(a, b). Es decir, la vista se actualiza al ejecutar un método, pasándole como parámetro el nuevo valor, mientras que en Vue la sincronización entre el modelo (los datos) y la vista se produce automáticamente.

Por eso hay gente que dice que React no es realmente reactivo mientras que Vue sí lo es y, por lo tanto, React debería llamarse Vue y Vue debería llamarse React 😆️

React Vue tweet