Rendering "glitches" in reactive programming

Dario Mannu - Jun 7 - - Dev Community

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.

. . . . . . . . . . . . . . . . . .