Why React re-renders so much and how to use signals to fix it
Learn how signals introduce fine-grained reactivity in React to eliminate traditional VDOM rendering bottlenecks in complex applications.
Summary
- Traditional VDOM forces React to recalculate entire component trees whenever any minor state changes in the application.
- Fine-grained reactivity with signals tracks dependencies directly at the text node or HTML attribute level.
- Entire components stop re-running repeatedly just because an isolated piece of data has been updated.
- Transitioning to atomic state patterns drastically reduces CPU usage in dense screens and long lists.
- Maintaining a clean architecture prevents codebases from turning into tangled webs of complex optimization hooks.
The invisible problem behind mass re-renders in React
Frontend developers know that modern ecosystems deliver powerful tools, but they exact a heavy performance toll as complexity grows. At the core of this dynamic is the Virtual DOM, a lightweight copy of the element tree that the framework keeps in memory to diff what changed on screen. In practice, this means that every time a small piece of data shifts, React has to re-execute entire component functions to generate this virtual tree and figure out where to apply the patch. In large applications with long lists, dynamic charts, or complex forms, this behavior causes noticeable stuttering, sluggish clicks, and a sharp drop in user experience.
To grasp the severity of this scenario, it is worth recalling similar bottlenecks faced across the web ecosystem, such as the need to use Web Workers to fix render bottlenecks and keep 60 FPS during heavy tasks. However, when the bottleneck stems from the UI state update logic itself, traditional Workers do not solve it alone, because the issue lies within the component's reactivity architecture. The framework's default model relies on the premise that the top of the tree must notify all lower branches whenever something changes, triggering cascades of unnecessary calls that consume precious browser processing cycles.
How signal-based reactivity changes the performance game
Signals arrive to break this cycle of cascading notifications, introducing a model where data directly notifies who needs it, without intermediaries. In practice, a signal is a small observable container that holds a value and knows precisely which parts of the interface are listening to its changes. When we alter the content of this container, only the exact DOM node displaying that value is updated, completely bypassing the parent component function and neighboring sibling components that have nothing to do with it.
This approach eliminates the need to guess where to apply excessive memoization using tools like useMemo and useCallback, which often cause more trouble than help when misapplied. To deepen this understanding of how to design efficient components without falling into unnecessary complexity traps, it is worth reviewing the concepts of Clean Architecture without the fluff: how to avoid over-engineering. By adopting atomic state, code maintainability improves dramatically, as business logic and data dependencies remain isolated and transparent from the very first line.
Implementing atomic states to bypass the traditional VDOM
Migrating to atomic patterns requires a shift in how we view the classic unidirectional data flow. Instead of propagating properties top-down across ten levels of components, we create shared state atoms that can be read and modified from anywhere safely and immediately. Below is a practical example of how to structure a reactive counter using the signal concept:
import { signal } from '@preact/signals-react';
const globalCounter = signal(0);
function IncrementButton() {
console.log('IncrementButton rendered');
return (
<button onClick={() => globalCounter.value++}>
Increment
</button>
);
}
function ValueDisplay() {
console.log('ValueDisplay rendered');
return <span>Current value: {globalCounter.value}</span>;
}In this simple example, clicking the button increments the signal value. The crucial detail that changes everything is that only the ValueDisplay component reacts to the change, while the IncrementButton component remains static, without re-executing its internal code. This level of isolation is what enables the construction of dense control panels and real-time applications that run smoothly even on mid-range mobile devices or older computers.
Challenges and pitfalls when adopting signals in legacy codebases
Although tempting, introducing signals into an existing project requires planning to avoid conflicts with the framework's traditional lifecycle. A common mistake is trying to mix atomic state with legacy properties in an unorganized way, creating hybrid flows that are hard to debug when a synchronization bug appears. To mitigate this type of operational risk at scale, it is worth studying isolation strategies similar to those applied when focusing on how to speed up React components with signals and fine-grained reactivity under heavy performance demands.
Another point of attention relates to managing side effects and asynchronous subscriptions within signals. Unlike traditional hooks that trigger based on dependency arrays prone to infinite loops, signals track reads automatically. However, if a side effect modifies multiple interconnected states without proper care, it can spawn cascading renders just as bad as the original VDOM, neutralizing the performance gain initially achieved.
Final thoughts on the future of reactivity in web development
The JavaScript ecosystem is moving consistently toward more efficient execution models, reducing the redundant work browsers must perform to render dynamic interfaces. Adopting signals and atomic state patterns represents not just an isolated technical optimization, but a natural evolution in how we design scalable and responsive applications. By understanding the limits of the traditional VDOM and embracing fine-grained reactivity, developers gain the ability to deliver robust software that respects the end user's hardware resources, ensuring fluidity and longevity for their projects.