Back to blog

Signals in JavaScript: TC39 Wants to Make Reactivity a Native Language Standard

Hello HaWkers, a proposal is shaking up the JavaScript world: Signals could become an official part of the language. This means native reactivity, without needing frameworks.

Angular, Vue, Solid, Svelte - all already use Signals. But React doesn't. Let's understand this divide and what it means for the future.

What Are Signals

Understanding the fundamental concept.

Primitive Reactivity

Signals are reactive values:

// Current TC39 proposal
const count = new Signal.State(0);

// Read the value
console.log(count.get()); // 0

// Update the value
count.set(1);

// Derived computation
const double = new Signal.Computed(() => count.get() * 2);

console.log(double.get()); // 2

Why This Matters

Difference from traditional state:

Without Signals (manual state):

let count = 0;
let double = count * 2;

// Problem: double doesn't update automatically
count = 5;
console.log(double); // Still 0! Not reactive

With Signals (reactive):

const count = new Signal.State(0);
const double = new Signal.Computed(() => count.get() * 2);

count.set(5);
console.log(double.get()); // 10 - Updates automatically!

How Frameworks Use Signals

Each framework has its implementation.

Vue 3

Signals under the name "ref":

import { ref, computed } from 'vue';

// State signal
const count = ref(0);

// Computed signal
const double = computed(() => count.value * 2);

// Template reacts automatically
<template>
  <button @click="count++">
    {{ count }} x 2 = {{ double }}
  </button>
</template>

Angular

Official Signals since Angular 16:

import { signal, computed, effect } from '@angular/core';

// State signal
const count = signal(0);

// Computed signal
const double = computed(() => count() * 2);

// Side effect
effect(() => {
  console.log(`Count is now: ${count()}`);
});

// Update
count.set(5);
count.update(n => n + 1);

Solid.js

Signals are the framework's core:

import { createSignal, createMemo, createEffect } from 'solid-js';

const [count, setCount] = createSignal(0);
const double = createMemo(() => count() * 2);

createEffect(() => {
  console.log(`Count: ${count()}, Double: ${double()}`);
});

// JSX is reactive at expression level
<button onClick={() => setCount(c => c + 1)}>
  {count()} x 2 = {double()}
</button>

Svelte 5 (Runes)

New syntax with runes:

<script>
  let count = $state(0);
  let double = $derived(count * 2);

  $effect(() => {
    console.log(`Count is ${count}`);
  });
</script>

<button onclick={() => count++}>
  {count} x 2 = {double}
</button>

Why React Doesn't Use Signals

The controversy explained.

Different Philosophy

React chose another path:

React's model (Virtual DOM):

function Counter() {
  const [count, setCount] = useState(0);
  const double = count * 2; // Recalculates on every render

  return (
    <button onClick={() => setCount(c => c + 1)}>
      {count} x 2 = {double}
    </button>
  );
}
// Entire component re-renders when count changes

Signals model (Granular reactivity):

function Counter() {
  const count = signal(0);
  const double = computed(() => count() * 2);

  return (
    <button onClick={() => count.set(c => c + 1)}>
      {count()} x 2 = {double()}
    </button>
  );
}
// Only the expressions {count()} and {double()} update

Trade-offs

Each approach has advantages:

Aspect React Hooks Signals
Performance Re-render component Granular update
Mental model Simple and predictable More complex
Debug React DevTools More difficult
Bundle size Larger Smaller
Server rendering Mature Evolving

React's Official Position

What the React team says:

"Signals are performance optimization, not a new paradigm. React prefers to keep the mental model simple and optimize under the hood."

React's strategy:

  • React Compiler (former React Forget)
  • Automatic memoization
  • Concurrent rendering
  • Server Components

The TC39 Proposal

What's being standardized.

Current Status

Committee progress:

Stage 1 (Proposal):

  • Approved in April 2024
  • Polyfill available
  • Experimental implementations
  • Active discussions

Proposed API

Planned interface:

// State signal
const counter = new Signal.State(0);

// Reading
counter.get(); // 0

// Writing
counter.set(1);

// Computed signal
const doubled = new Signal.Computed(() => counter.get() * 2);

// Read only
doubled.get(); // 2

// Watcher for effects
const watcher = new Signal.subtle.Watcher(() => {
  // Notifies when observed signals change
  console.log("Something changed!");
});

watcher.watch(doubled);

Why In The Browser

Benefits of having it native:

1. Interoperability:

// Vue signals working with Angular
import { ref } from 'vue';
import { signal } from '@angular/core';

// Today: Incompatible
// With standard: Interchangeable

2. Performance:

  • Native C++ implementation
  • Engine optimizations
  • Less abstraction overhead
  • Better DOM integration

3. Consistency:

  • Same API across all frameworks
  • Code portability
  • Unified documentation
  • Less fragmentation

Impact On Frameworks

What changes for each one.

Vue

Easier migration:

// Vue 3 today
import { ref, computed } from 'vue';
const count = ref(0);

// Vue future (possible)
const count = new Signal.State(0);
// Vue adds only convenience layers

Angular

Already prepared:

// Angular today already has similar API
import { signal, computed } from '@angular/core';

// Migration to native would be transparent
// Mainly performance gains

Solid

Validates the approach:

// Solid already uses very similar API
// Would be almost drop-in replacement
// Ryan Carniato is involved in the proposal

React

Pressure to adapt:

Possible scenarios:

  1. React ignores and keeps current approach
  2. React creates compatibility layer
  3. React offers optional "signals" mode
  4. New dominant framework emerges

Performance In Practice

Real benchmarks.

Framework Comparison

10,000 item update test:

Framework Time (ms) Memory (MB)
Vanilla + Signals 12 8
Solid.js 14 10
Vue 3 18 12
Svelte 5 16 11
Angular 19 22 15
React 19 45 28

When Signals Shine

Ideal use cases:

Dashboards with lots of data:

// With Virtual DOM: Everything re-renders
// With Signals: Only changed cells update

const cells = Array(10000).fill(null).map(() =>
  new Signal.State(Math.random())
);

// Update one cell: O(1) with Signals
cells[5000].set(0.5);

Complex forms:

// Reactive and granular validation
const email = new Signal.State('');
const isValid = new Signal.Computed(() =>
  email.get().includes('@')
);

// Only the validation indicator updates

Animations and games:

// 60fps updates
const position = new Signal.State({ x: 0, y: 0 });

// Minimum overhead per frame
requestAnimationFrame(() => {
  position.set({ x: position.get().x + 1, y: 0 });
});

Using Signals Today

How to experiment now.

Official Polyfill

Installation and usage:

npm install signal-polyfill
import { Signal } from 'signal-polyfill';

const count = new Signal.State(0);
const double = new Signal.Computed(() => count.get() * 2);

// Works in any environment
console.log(double.get()); // 0

count.set(5);
console.log(double.get()); // 10

Production-Ready Frameworks

Options for production:

If you want Signals today:

  1. Solid.js - Purest in Signals
  2. Vue 3 - Signals as "refs"
  3. Angular 17+ - Official Signals
  4. Svelte 5 - Runes (Signals with syntax)

Standalone libraries:

  • Preact Signals
  • @preact/signals-core
  • MobX (similar concept)

The Future

Where we're headed.

Likely Timeline

Realistic expectations:

2026:

  • Stage 2 of proposal
  • Stable polyfills
  • Browser experiments

2027:

  • Stage 3 (candidate)
  • Native implementations begin
  • Frameworks adapting

2028+:

  • Stage 4 (finalized)
  • Available in browsers
  • New era of frameworks

Career Impact

What developers should do:

Short term:

  • Understand the Signals concept
  • Experiment in personal projects
  • Continue using your current framework

Medium term:

  • Follow the TC39 proposal
  • Evaluate Solid/Vue/Angular
  • Prepare for changes

Long term:

  • Signals will be base knowledge
  • Frameworks will converge
  • New architectures will emerge

Conclusion

Signals represents a possible unification of the JavaScript ecosystem. Whether the proposal is approved or not, the concept already dominates modern frameworks - Angular, Vue, Solid, Svelte all converge on this approach.

React continues on its own path, but pressure increases. Time will tell if Virtual DOM remains competitive or if Signals becomes the standard.

For developers, the advice is: understand the concept now. Whatever the outcome, granular reactivity is a clear trend.

If you want to strengthen your JavaScript foundation, check out our article on ES2026 and Temporal API to see other important language news.

Let's go! 🦅

💻 Master JavaScript for Real

The knowledge you gained in this article is just the beginning. Understanding fundamental concepts like reactivity requires a solid language foundation.

Invest in Your Future

I've prepared complete material for you to master JavaScript:

Payment options:

  • 1x of $4.90 no interest
  • or $4.90 at sight

📖 View Complete Content

Comments (0)

This article has no comments yet 😢. Be the first! 🚀🦅

Add comments