Skip to content

Performance Comparison

React Paradigm vs SigJS Paradigm

When building modern web applications, managing state and rendering efficiently is critical for delivering a smooth user experience.
In this article, we’ll compare the paradigms of React and SigJS by implementing the same app in both frameworks. The app demonstrates a color grid with a modal that follows the mouse position and displays the hovered color.
Additionally, it includes a computationally expensive component (HeavyComputationComponent) to highlight the performance differences between the two paradigms.





TL;DR:

In this comparison, the core difference lies in how UI updates are handled.
In React, when state changes, the component where the change occurred—and all of its children—are re-executed. This means even unrelated parts of the UI may rerun unless explicitly optimized with memo or hooks like useMemo.
In contrast, SigJS updates the DOM directly by streaming only the changed signal values to the elements that depend on them—without re-executing any component functions. This leads to more efficient updates with no manual optimization needed.





React Paradigm

In React, state changes trigger a re-render of the component holding the state and all its child components. This means that even if only a small part of the UI needs to update, React will reconstruct the entire virtual DOM subtree for the component and its children.
While React uses reconciliation to minimize actual DOM updates, the re-rendering process (re-executed component functions) can still be computationally expensive. especially when heavy computations are involved.


React Implementation

Here’s the React implementation of the app:


React Implementation Summary

In the React implementation:

  • Mouse movement updates state via setMousePosition and setHoveredColor.
  • These updates trigger a re-render of the root component, including HeavyComputationComponent.
  • As a result, the HeavyComputationComponent recalculates fibonacci(40) on each update, even though its output is static.
  • The modal’s position lags significantly behind the mouse during movement due to the rendering cost.

SigJS Paradigm

In SigJS, state is managed using signals, which are reactive primitives. When a signal’s value changes, only the DOM elements or subscribers connected to that signal are updated. Components themselves do not re-render unless explicitly required. This eliminates unnecessary computations and ensures efficient updates.


SigJS Implementation

Here’s the SigJS implementation of the same app:


SigJS Implementation Summary

  • mousePosition and hoveredColor are signals.
  • Updates to these signals only affect DOM nodes that read from them.
  • The HeavyComputationComponent is rendered once and does not respond to signal changes, avoiding unnecessary recomputation.
  • The modal remains responsive to mouse movements regardless of computational load elsewhere in the application.

Key Behavioral Differences

AspectReactSigJS
State PropagationTriggers full component subtree re-rendersUpdates only signal-dependent elements
Computation IsolationRequires manual memoization (useMemo, etc.)Isolated by default; unaffected unless subscribed to signals
Update GranularityComponent-levelDOM element-level
Rendering ModelVirtual DOM diffingDirect reactive bindings
Performance Under LoadDegrades with frequent state changesRemains stable due to fine-grained updates

Conclusion

The SigJS paradigm offers a significant performance advantage by avoiding unnecessary re-renders and isolating updates to only the affected DOM elements. This makes it an excellent choice for applications where performance is critical, especially when dealing with frequent state changes or heavy computations.

By adopting SigJS, developers can achieve smoother user experiences with less effort, as demonstrated in this color grid app. While React is a powerful and widely-used library, SigJS provides a compelling alternative for scenarios where fine-grained reactivity and performance are paramount.

This comparison highlights the differences between component-based and signal-based rendering models in the context of dynamic UIs with independent reactive elements and costly computation.