Voltar para o Blog

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.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário