Signals: O Novo Padrao de Reatividade que Esta Unindo os Frameworks JavaScript
Ola HaWkers, algo interessante esta acontecendo no ecossistema JavaScript: depois de anos de cada framework ter sua propria abordagem para gerenciamento de estado, um padrao esta emergindo - Signals.
Angular, Vue, Svelte e Solid agora usam Signals para reatividade. E ha um movimento para adicionar Signals diretamente as especificacoes do JavaScript.
O Que Sao Signals?
Signals sao primitivas de reatividade que permitem rastrear e propagar mudancas de estado de forma eficiente. Diferente do modelo de Virtual DOM usado pelo React, Signals atualizam apenas as partes da UI que realmente mudaram.
Conceitos fundamentais:
- Signal: Um container de valor que pode ser observado
- Computed: Um valor derivado que recalcula automaticamente quando suas dependencias mudam
- Effect: Uma funcao que executa automaticamente quando Signals que ela usa mudam
// Exemplo conceitual de Signals
import { signal, computed, effect } from 'signals';
// Criar um signal
const count = signal(0);
// Criar um valor computado
const doubled = computed(() => count.value * 2);
// Criar um efeito
effect(() => {
console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);
});
// Atualizar o signal - efeito executa automaticamente
count.value = 5;
// Output: "Count: 5, Doubled: 10"
Por Que Signals Estao se Tornando Padrao?
1. Performance Superior
O modelo de Virtual DOM do React requer reconciliacao de toda a arvore de componentes para detectar mudancas. Signals atualizam cirurgicamente apenas o que mudou.
Comparacao simplificada:
| Abordagem | Quando Atualiza | Overhead |
|---|---|---|
| Virtual DOM | Re-renderiza componente inteiro | Alto |
| Signals | Atualiza apenas binding especifico | Minimo |
2. Previsibilidade
Com Signals, o fluxo de dados e explicito. Voce sabe exatamente o que depende de que:
// Dependencias sao rastreadas automaticamente
const firstName = signal('John');
const lastName = signal('Doe');
// Este computed depende de firstName e lastName
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// Mudanca em firstName atualiza fullName automaticamente
firstName.value = 'Jane';
// fullName agora e "Jane Doe"3. Sem Re-renders Desnecessarios
No React, qualquer mudanca de estado pode causar re-render de toda a arvore de componentes filhos. Com Signals, apenas os bindings afetados atualizam.
Signals nos Principais Frameworks
Angular Signals
Angular introduziu Signals na versao 16 e agora e a abordagem recomendada:
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 uma abordagem similar com ref e 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 }} e {{ doubled }}Svelte 5 Runes
Svelte 5 introduziu "runes" - sua versao 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 foi pioneiro nesse modelo e influenciou todos os outros:
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>
);
}
A Proposta TC39 para Signals Nativos
Ha uma proposta ativa no TC39 (comite que define o padrao JavaScript) para adicionar Signals nativamente a linguagem.
Beneficios de Signals nativos:
- Interoperabilidade entre frameworks
- Performance otimizada pelo engine
- API padronizada
- Menor bundle size (nao precisa importar de biblioteca)
A proposta ainda esta em estagios iniciais, mas o suporte da industria e forte.
Como Seria Signals Nativo?
// Possivel sintaxe futura (especulativa)
const count = Signal.state(0);
const doubled = Signal.computed(() => count.get() * 2);
Signal.effect(() => {
console.log(`Count: ${count.get()}`);
});
count.set(5);
E o React?
React segue um caminho diferente com seu modelo de Virtual DOM e hooks. O React Compiler (anteriormente React Forget) busca otimizar automaticamente re-renders.
Posicao do React:
- Nao planeja adotar Signals no core
- React Compiler + Server Components e a estrategia de performance
- Bibliotecas como Jotai e Zustand oferecem APIs similares a Signals
💡 Nota: Voce pode usar bibliotecas de Signals com React, mas nao e a abordagem idiomatica do framework.
Implementando Signals do Zero
Para entender como funcionam, vamos criar uma versao simplificada:
// Mini implementacao 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(); // Executa para coletar 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"
Quando Usar Signals vs Outras Abordagens
Signals sao ideais para:
- Estado de UI local
- Formularios complexos
- Atualizacoes frequentes de pequenas partes da UI
- Aplicacoes que precisam de performance maxima
Outras abordagens podem ser melhores para:
- Estado de servidor (React Query, TanStack Query)
- Estado global muito complexo
- Aplicacoes onde simplicidade > performance
Conclusao
Signals representam uma convergencia interessante no ecossistema JavaScript. Depois de anos de abordagens divergentes, os principais frameworks estao adotando um modelo similar de reatividade fine-grained.
Para desenvolvedores, isso significa que conceitos aprendidos em um framework transferem facilmente para outros. E se a proposta TC39 for aprovada, poderemos ter Signals nativos no JavaScript.
Se voce se interessa por tendencias de JavaScript e frameworks, recomendo que de uma olhada em outro artigo: Por Que Desenvolvedores Estao Abandonando Frameworks e Voltando Para Vanilla JavaScript onde voce vai descobrir o outro lado dessa discussao.

