Signals no JavaScript: O Padrao Nativo de Reatividade Que Esta Chegando
Olá HaWkers, uma das propostas mais empolgantes para o futuro do JavaScript está ganhando força. Os Signals, um padrão de reatividade já adotado por frameworks como Angular, Vue, Solid e Svelte, podem em breve se tornar parte nativa da linguagem JavaScript.
Você está pronto para uma mudança que pode unificar como todos os frameworks lidam com estado reativo?
O Que São Signals
Signals são primitivas de reatividade que permitem criar valores observáveis que automaticamente notificam dependentes quando mudam. Diferente de soluções como Redux ou Context API, Signals são granulares e eficientes por design.
Conceito Básico
// Proposta atual de Signals nativos
// (sintaxe pode mudar até a aprovação final)
// Criando um signal
const count = new Signal.State(0);
// Lendo o valor
console.log(count.get()); // 0
// Atualizando o valor
count.set(1);
// Valores computados que reagem automaticamente
const doubled = new Signal.Computed(() => count.get() * 2);
console.log(doubled.get()); // 2
// Quando count muda, doubled atualiza automaticamente
count.set(5);
console.log(doubled.get()); // 10Contexto importante: A proposta está sendo desenvolvida pelo TC39 (comitê que define o ECMAScript) com contribuições de engenheiros do Angular, Vue, Solid e outros frameworks.
Por Que Signals São Importantes
A reatividade é fundamental para interfaces modernas, mas cada framework implementa sua própria solução. Isso causa fragmentação e dificulta a interoperabilidade.
O Problema Atual
Cada framework tem sua abordagem:
- React: Virtual DOM + reconciliação
- Vue: Proxies + sistema de reatividade próprio
- Angular: Zone.js + signals (recente)
- Solid: Signals + compilação
- Svelte: Compilação + reatividade em tempo de build
Consequências:
- Código não portável entre frameworks
- Bibliotecas precisam de wrappers para cada framework
- Desenvolvedores aprendem sistemas diferentes
- Performance varia muito entre implementações
A Solução: Signals Nativos
// Com signals nativos, bibliotecas podem ser agnósticas
// Uma biblioteca de estado que funciona em qualquer lugar
class Counter {
#count = new Signal.State(0);
get count() {
return this.#count.get();
}
increment() {
this.#count.set(this.#count.get() + 1);
}
decrement() {
this.#count.set(this.#count.get() - 1);
}
}
// Funciona com React, Vue, Angular, Solid, Svelte...
const counter = new Counter();
Como Signals Funcionam
Signals são baseados em um grafo de dependências que rastreia automaticamente quais valores dependem de quais.
Arquitetura Básica
// Signal.State: valores que podem ser lidos e escritos
const firstName = new Signal.State("John");
const lastName = new Signal.State("Doe");
// Signal.Computed: valores derivados (somente leitura)
const fullName = new Signal.Computed(() => {
// Dependências são rastreadas automaticamente
return `${firstName.get()} ${lastName.get()}`;
});
console.log(fullName.get()); // "John Doe"
// Apenas firstName é atualizado
firstName.set("Jane");
// fullName recalcula automaticamente apenas o necessário
console.log(fullName.get()); // "Jane Doe"Efeitos e Reações
// Signal.subtle.Watcher: observar mudanças
const watcher = new Signal.subtle.Watcher(() => {
console.log("Algum signal monitorado mudou!");
});
// Adicionar signals para monitorar
watcher.watch(firstName);
watcher.watch(lastName);
// Quando qualquer um mudar, o callback é chamado
firstName.set("Alice"); // Log: "Algum signal monitorado mudou!"Batching Automático
// Múltiplas atualizações são agrupadas eficientemente
const items = new Signal.State([]);
const filter = new Signal.State("");
const filteredItems = new Signal.Computed(() => {
const f = filter.get();
return items.get().filter(item => item.includes(f));
});
// Mesmo com múltiplas atualizações...
items.set(["apple", "banana", "cherry"]);
filter.set("a");
// ...o computed só recalcula uma vez
console.log(filteredItems.get()); // ["apple", "banana"]
Comparação Com Soluções Atuais
Veja como Signals nativos se comparam com as abordagens atuais.
React useState vs Signals
// React: useState
function Counter() {
const [count, setCount] = useState(0);
const doubled = count * 2; // Recalcula em todo render
return (
<div>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
// Com Signals (conceitual)
function Counter() {
const count = useSignal(0);
const doubled = useComputed(() => count.value * 2);
return (
<div>
<p>Count: {count.value}</p>
<p>Doubled: {doubled.value}</p>
<button onClick={() => count.value++}>+</button>
</div>
);
}Vue Reactivity vs Signals
// Vue: ref e computed
import { ref, computed } from 'vue';
const count = ref(0);
const doubled = computed(() => count.value * 2);
// Signals nativos (similar, mas padronizado)
const count = new Signal.State(0);
const doubled = new Signal.Computed(() => count.get() * 2);Solid Signals (já usa o padrão)
// Solid: signals (inspiração principal)
import { createSignal, createMemo } from 'solid-js';
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
// Signals nativos (muito similar)
const count = new Signal.State(0);
const doubled = new Signal.Computed(() => count.get() * 2);
Benefícios Para Desenvolvedores
A adoção de Signals nativos trará vários benefícios.
Performance Granular
// Signals atualizam apenas o que precisa atualizar
const todos = new Signal.State([
{ id: 1, text: "Learn Signals", done: false },
{ id: 2, text: "Build app", done: false },
]);
const completedCount = new Signal.Computed(() => {
return todos.get().filter(t => t.done).length;
});
const pendingCount = new Signal.Computed(() => {
return todos.get().filter(t => !t.done).length;
});
// Se apenas 'done' de um item mudar,
// apenas os computeds relevantes recalculamCódigo Mais Simples
// Sem signals: gerenciamento manual de estado
class Store {
constructor() {
this.state = { count: 0 };
this.listeners = [];
}
subscribe(listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter(l => l !== listener);
};
}
increment() {
this.state.count++;
this.listeners.forEach(l => l(this.state));
}
}
// Com signals: reatividade automática
class Store {
count = new Signal.State(0);
increment() {
this.count.set(this.count.get() + 1);
}
}Debugging Melhor
// Signals permitem rastrear dependências facilmente
const a = new Signal.State(1);
const b = new Signal.State(2);
const c = new Signal.Computed(() => a.get() + b.get());
const d = new Signal.Computed(() => c.get() * 2);
// DevTools podem mostrar:
// d depende de c
// c depende de a e b
// Quando a muda, c e d são recalculados
Estado Atual da Proposta
A proposta de Signals está em desenvolvimento ativo no TC39.
Timeline Esperado
2024:
- Stage 1: Proposta inicial aceita
- Discussões sobre API e semântica
2025:
- Stage 2: Especificação em draft
- Implementações experimentais em engines
- Polyfills disponíveis
2026-2027 (estimativa):
- Stage 3: Candidato a implementação
- Browsers começam implementações
2027+ (estimativa):
- Stage 4: Aprovação final
- Disponível em todos os browsers modernos
Participantes Principais
| Organização | Contribuição |
|---|---|
| Angular Team | Co-autores da proposta |
| Vue.js Core | Consultoria técnica |
| Solid.js | Inspiração do design |
| Bloomberg | Patrocínio e engenharia |
| TC39 | Processo de padronização |
Como Se Preparar
Você pode começar a entender Signals hoje.
Aprenda Solid.js
// Solid tem a API mais próxima da proposta
import { createSignal, createEffect } from 'solid-js';
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log("Count changed:", count());
});
setCount(1); // Log: "Count changed: 1"Explore Angular Signals
// Angular 16+ usa signals nativamente
import { signal, computed, effect } from '@angular/core';
const count = signal(0);
const doubled = computed(() => count() * 2);
effect(() => {
console.log(`Count: ${count()}, Doubled: ${doubled()}`);
});
count.set(5); // Log: "Count: 5, Doubled: 10"Use o Polyfill
// signal-polyfill disponível via npm
import { Signal } from 'signal-polyfill';
const count = new Signal.State(0);
const doubled = new Signal.Computed(() => count.get() * 2);
Conclusão
Signals nativos no JavaScript representam uma mudança fundamental em como construímos aplicações reativas. Ao padronizar a reatividade na linguagem, ganhamos interoperabilidade entre frameworks, performance consistente e código mais simples.
Embora a proposta ainda esteja em desenvolvimento, os conceitos já estão disponíveis em frameworks como Solid e Angular. Aprender sobre Signals hoje é investir no futuro do desenvolvimento web.
Se você quer entender mais sobre as tendências que estão moldando o JavaScript moderno, recomendo dar uma olhada em nosso artigo sobre VoidZero e Vite Plus onde discutimos a nova geração de ferramentas JavaScript.

