React has given web developers a rock-solid way to build user interfaces for more than ten years, but its “re-render the whole component” rule can still waste work. When a single piece of state changes, React redraws every JSX node in that component and all of its children. On a small demo, you hardly notice, yet in a complex dashboard, the repaint cost causes noticeable stuttering and high CPU usage. The standard escape hatch, wrapping parts of the tree in memo, adding useCallback, and hand-tuning dependency arrays in useEffect, works, but it turns code reviews into performance audits instead of feature work. Signals aim to fix that.
A signal is a tiny reactive value that tracks which pieces of code read it. When you call count. value while rendering a text node, the signal attaches that text node to its subscriber list. Later, when count.value++ runs, the signal walks its list, and updates only those subscribers. No other nodes re-render, and no virtual-DOM diff is necessary. SolidJS and Preact already rely on this approach, and both frameworks show it scales from basic counters to live trading charts without extra tuning.
Because Preact’s API is almost a drop-in replacement for React, its team released @preact/signals for Preact itself and @preact/signals-react for ordinary React projects. The React wrapper can replace the usual hook trio, useState, useEffect, and useMemo, with a single call to signal(). Teams that switched report smaller bundles and faster updates before any other optimization. One benchmark that updated 20 000 text nodes every animation frame found React with vanilla hooks struggling to stay near 30 fps, while Preact with signals held a steady 60 fps at lower memory cost. React still rebuilds a whole component to discover what changed; a signal already knows exactly which DOM nodes depend on it.
The React core team is watching. Since 2023 they’ve shipped weekly “Canary” builds that include experimental features thought to be close to production-ready. Contributors reading those commits have spotted work on “concurrent stores” or “fine-grained stores”, cells that behave like signals and plug straight into React’s scheduler. While no stable API exists yet, the presence of this work in React’s own repo is a clear sign the idea is under serious consideration.
JavaScript’s standards body, TC39, is also involved. A Stage-1 proposal aims to add signals to the language itself so every framework can share the same reactive primitive. The draft argues that today’s state tools, Redux stores, Vue refs, Svelte stores, are all tied to their own view layers. A built-in signal would let libraries expose reactive data without importing a UI framework at all, giving React one more reason to align with the trend.
If React ships native signals, the immediate upside is performance with less effort. Instead of juggling half a dozen memo helpers, you’d model state directly as signals and let React patch only what matters, no more missed dependencies or accidental infinite loops in useEffect. Large lists would refresh more quickly because React could ignore rows that stayed the same, and the lighter workload would leave extra CPU headroom for animations and other concurrent tasks.
Signals trim bundle size, too. The runtime logic is lighter than virtual-DOM diffing, so code-split chunks shrink, crucial on slower mobile networks where every kilobyte hurts conversion.
There are trade-offs. Debugging shifts from “why did my component re-render?” to “why did this signal fire?” React DevTools today shows a flame chart of component cost; it will need a graph view for signal dependencies. Mixing hooks and signals in one component also raises timing questions: should a signal write trigger the whole component to run again or just patch the DOM in place? Whatever default React chooses will surprise part of the community.
Library authors will need guidance, too. Packages that expose a context provider might switch to a signal so consumers update automatically, but that’s a breaking change, callers must read .value instead of a plain object. While codemods help, any migration means churn.
Teaching signals is simpler because a reactive value looks like a regular variable, yet newcomers can shoot themselves in the foot by mutating deep objects. SolidJS solves that with helpers like createStore; React will need clear docs on the edge cases.
If you want to try signals today, the safest path is to wrap one interactive widget, say, a live price ticker, in @preact/signals-react and measure real-world timing before and after. For performance-critical views, you can embed a small Preact or Lit island that handles high-frequency updates, keeping the rest of the page on classic hooks. The extra bundle weight is often outweighed by smoother interactions.
The Lit project shows a broader future: in late 2024 it adopted signals for Web Components, proving the pattern isn’t tied to any single library. If Lit and React end up sharing a standardized signal, passing reactive data between them could be as simple as importing a module, making framework-agnostic UI logic truly practical.
Signals tackle a pain React developers know: wasted renders and the boilerplate written to avoid them. Preact and SolidJS have already proven the concept in production, and React’s Canary builds show the core team is experimenting with something similar. Pros include less code, faster updates, and smaller bundles; cons include a new debugging model and some migration friction. Testing the approach now, following the TC39 draft, and watching Canary release notes are the best ways to stay ahead of whatever shape React’s official signal API takes.