DEV Community

Dario Mannu
Dario Mannu

Posted on

1

Rendering "glitches" in reactive programming

Rendering glitches are a bit like the reactive world's version of the race condition where some derived state causes the rendering of invalid data before all its dependencies have finished updating.

Image description

In this scenario, we have A, the main state, a counter that emits a sequence of numbers.

Next we have B, a derived state that simply emits A +1.

Then we have C, another derived state, derived from both.

Now, if A emits a value before B, the relationship a < b won't hold and a false value will be emitted.
If B emits before A, it will always be OK.

How do we make sure this won't happen?
Depending on what reactive paradigm is being used, programs may or may not be exposed to these scenarios.

Basic reactive patterns like "Signals" or "Hooks" can be particularly vulnerable (in fact, the first time I heard about rendering glitches myself was when I was reading about Signals).

The result can be an ever increasing number of unnecessary re-renders, causing poor performance, laptops getting hot, etc.

Solutions exist in the form of both tactical and strategical approaches. Tactical means "deal with it and make sure it doesn't happen in your code", although some efforts are being made to address these issues by the very supporters of the signal pattern.

Another approach, more strategic, is relying on a programming paradigm that's simply immune to these situations.

Take RxJS, for example, the most well-established FRP library for JavaScript. The way you address issues like the above is with dedicated control-flow operators, through which the above becomes a non-problem.

const A = interval(1000); // emits 0, 1, 2, ... every second
const B = A.pipe(
  map(a => a+1)           // re-emits 1, 2, 3, ...
);

const C = zip(A, B).pipe(
  map(([a, b]) => a < b)  // emits true | false
);
Enter fullscreen mode Exit fullscreen mode

zip is one of the most basic RxJS flow-control operators. It simply waits for both sources to emit before moving forward.
This way, a rendering glitch can simply never happen.

There are some UI frameworks like Cycle or libraries like Rimmel that take full advantage of RxJS and its operators are first-class citizens, so your components never really have to deal with rendering glitches.

N.B.: we talk about "glitches", when the flow is beyond our control, like in the case of many Signal implementations. With Observables and RxJS the flow control is always in your hands.

If you still experience inconsistencies using RxJS and Observable streams, those would most likely fall into the simpler "application bug" category rather than qualify as a "glitch".

Circular Dependencies

There also appears to be an interesting case with circular dependencies. When derived state is connected creating loops, it's particularly challenging to resolve the rendering glitch problem, which again is not a problem in a flow-controlled reactive solution using Observables.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more