Signals: El Nuevo Estandar de Reactividad que Esta Uniendo los Frameworks JavaScript
Hola HaWkers, algo interesante esta pasando en el ecosistema JavaScript: despues de anos de que cada framework tuviera su propio enfoque para el manejo de estado, un estandar esta emergiendo - Signals.
Angular, Vue, Svelte y Solid ahora usan Signals para reactividad. Y hay un movimiento para agregar Signals directamente a las especificaciones de JavaScript.
Que Son Signals?
Signals son primitivas de reactividad que permiten rastrear y propagar cambios de estado de manera eficiente. A diferencia del modelo de Virtual DOM usado por React, Signals actualizan solo las partes de la UI que realmente cambiaron.
Conceptos fundamentales:
- Signal: Un contenedor de valor que puede ser observado
- Computed: Un valor derivado que recalcula automaticamente cuando sus dependencias cambian
- Effect: Una funcion que ejecuta automaticamente cuando los Signals que usa cambian
// Ejemplo conceptual de Signals
import { signal, computed, effect } from 'signals';
// Crear un signal
const count = signal(0);
// Crear un valor computado
const doubled = computed(() => count.value * 2);
// Crear un efecto
effect(() => {
console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);
});
// Actualizar el signal - efecto ejecuta automaticamente
count.value = 5;
// Output: "Count: 5, Doubled: 10"
Por Que Signals Se Estan Convirtiendo en Estandar?
1. Performance Superior
El modelo de Virtual DOM de React requiere reconciliacion de todo el arbol de componentes para detectar cambios. Signals actualizan quirurgicamente solo lo que cambio.
Comparacion simplificada:
| Enfoque | Cuando Actualiza | Overhead |
|---|---|---|
| Virtual DOM | Re-renderiza componente completo | Alto |
| Signals | Actualiza solo binding especifico | Minimo |
2. Previsibilidad
Con Signals, el flujo de datos es explicito. Sabes exactamente que depende de que:
// Dependencias son rastreadas automaticamente
const firstName = signal('John');
const lastName = signal('Doe');
// Este computed depende de firstName y lastName
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// Cambio en firstName actualiza fullName automaticamente
firstName.value = 'Jane';
// fullName ahora es "Jane Doe"3. Sin Re-renders Innecesarios
En React, cualquier cambio de estado puede causar re-render de todo el arbol de componentes hijos. Con Signals, solo los bindings afectados se actualizan.
Signals en los Principales Frameworks
Angular Signals
Angular introdujo Signals en la version 16 y ahora es el enfoque recomendado:
import { signal, computed, effect } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<p>Count: {{ count() }}</p>
<p>Doubled: {{ doubled() }}</p>
<button (click)="increment()">+</button>
`
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
constructor() {
effect(() => {
console.log('Count changed:', this.count());
});
}
increment() {
this.count.update(c => c + 1);
}
}Vue 3 Reactivity
Vue usa un enfoque similar con ref y computed:
import { ref, computed, watchEffect } from 'vue';
const count = ref(0);
const doubled = computed(() => count.value * 2);
watchEffect(() => {
console.log('Count changed:', count.value);
});
// Template usa automaticamente
// {{ count }} y {{ doubled }}Svelte 5 Runes
Svelte 5 introdujo "runes" - su version de Signals:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
console.log('Count changed:', count);
});
</script>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onclick={() => count++}>+</button>SolidJS
Solid fue pionero en este modelo e influencio a todos los demas:
import { createSignal, createEffect, createMemo } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
createEffect(() => {
console.log('Count changed:', count());
});
return (
<div>
<p>Count: {count()}</p>
<p>Doubled: {doubled()}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
La Propuesta TC39 para Signals Nativos
Hay una propuesta activa en TC39 (el comite que define el estandar JavaScript) para agregar Signals nativamente al lenguaje.
Beneficios de Signals nativos:
- Interoperabilidad entre frameworks
- Performance optimizada por el engine
- API estandarizada
- Menor bundle size (no necesita importar de biblioteca)
La propuesta aun esta en etapas iniciales, pero el soporte de la industria es fuerte.
Como Serian Signals Nativos?
// Posible sintaxis futura (especulativa)
const count = Signal.state(0);
const doubled = Signal.computed(() => count.get() * 2);
Signal.effect(() => {
console.log(`Count: ${count.get()}`);
});
count.set(5);
Y React?
React sigue un camino diferente con su modelo de Virtual DOM y hooks. El React Compiler (anteriormente React Forget) busca optimizar automaticamente los re-renders.
Posicion de React:
- No planea adoptar Signals en el core
- React Compiler + Server Components es la estrategia de performance
- Bibliotecas como Jotai y Zustand ofrecen APIs similares a Signals
💡 Nota: Puedes usar bibliotecas de Signals con React, pero no es el enfoque idiomatico del framework.
Implementando Signals desde Cero
Para entender como funcionan, vamos a crear una version simplificada:
// Mini implementacion de Signals
let currentEffect = null;
function createSignal(initialValue) {
let value = initialValue;
const subscribers = new Set();
const read = () => {
if (currentEffect) {
subscribers.add(currentEffect);
}
return value;
};
const write = (newValue) => {
value = newValue;
subscribers.forEach(fn => fn());
};
return [read, write];
}
function createEffect(fn) {
currentEffect = fn;
fn(); // Ejecuta para recolectar dependencias
currentEffect = null;
}
function createMemo(fn) {
const [getValue, setValue] = createSignal();
createEffect(() => {
setValue(fn());
});
return getValue;
}
// Uso
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
createEffect(() => {
console.log(`Count: ${count()}, Doubled: ${doubled()}`);
});
setCount(5); // Log: "Count: 5, Doubled: 10"
Cuando Usar Signals vs Otros Enfoques
Signals son ideales para:
- Estado de UI local
- Formularios complejos
- Actualizaciones frecuentes de pequenas partes de la UI
- Aplicaciones que necesitan performance maxima
Otros enfoques pueden ser mejores para:
- Estado de servidor (React Query, TanStack Query)
- Estado global muy complejo
- Aplicaciones donde simplicidad > performance
Conclusion
Signals representan una convergencia interesante en el ecosistema JavaScript. Despues de anos de enfoques divergentes, los principales frameworks estan adoptando un modelo similar de reactividad fine-grained.
Para desarrolladores, esto significa que conceptos aprendidos en un framework se transfieren facilmente a otros. Y si la propuesta TC39 es aprobada, podremos tener Signals nativos en JavaScript.
Si te interesan las tendencias de JavaScript y frameworks, te recomiendo que le eches un vistazo a otro articulo: Por Que los Desarrolladores Estan Abandonando Frameworks y Volviendo a Vanilla JavaScript donde descubriras el otro lado de esta discusion.

