React was losing the performance war.
Until now.
For the last 3 years, the frontend world has been shouting one word: Signals. Frameworks like SolidJS and Preact proved that you don't need a Virtual DOM to build UIs. They showed us "fine-grained reactivity" where updates are surgical.
The Threat: React's top-down re-rendering model looked outdated. "Why re-render the whole component just to change one text node?" asked the signals crowd. They were right.
The Empire Strikes Back: React 19 didn't adopt signals. It didn't change the API. Instead, it introduced a Compiler that auto-memoizes everything, effectively achieving the performance of signals while keeping the mental model of simple variables.
02. How Signals Work (The Competition)
In a signals-based framework (like Solid), a component runs once. It sets up a dependency graph. When a signal changes, it doesn't re-run the user's function; it directly updates the specific DOM node subscribed to that signal.
// SolidJS / Signals Style
const Count = () => {
const [count, setCount] = createSignal(0);
// This console log runs ONCE, ever.
console.log("Component setup");
return (
<div>
{/*
When count changes, ONLY this text node updates.
The component function does NOT re-execute.
*/}
{count()}
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
};
03. React's Response: The Compiler
React still re-runs the component function. However, the React Compiler detects which parts of the JSX depend on changed values and which don't.
It essentially wraps every meaningful chunk of UI in a super-optimized useMemo. So while the function technically runs, the heavy Virtual DOM work is skipped for anything that hasn't changed.
The Result: The performance gap has narrowed to negligible levels for 99% of apps, but you get to keep using standard JavaScript values instead of calling getters count() everywhere.