Reactive Data Without the Async Headaches

Published: (March 4, 2026 at 06:06 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Robert Sanders

Modern frontend development often turns into a battle with async code:

  • async/await
  • subscriptions
  • dependency arrays
  • memoization
  • race conditions
  • unnecessary recomputations

What if you could simply describe your data and let the system handle the rest?

That’s exactly the idea behind rs‑x.

To demonstrate it, I built a small demo that tracks the real‑time position of the International Space Station (ISS).

👉 Live demo:


The Idea

The demo polls a public ISS API and exposes the data as part of a reactive model.

⚠️ Note: If many people open the demo simultaneously, the public ISS API may return Too Many Requests errors due to rate limits.

The API returns:

  • timestamp
  • latitude
  • longitude
  • altitude
  • velocity

At the same time the model contains an expensive computation to demonstrate how rs‑x handles dependencies.

Key idea: Only recompute what actually depends on changed data.


The Demo

The API is polled every few seconds using RxJS.

const $ = api.rxjs;
const rsx = api.rsx;

const issRaw$ = $.interval(2000).pipe(
  $.startWith(0),
  $.switchMap(() =>
    $.from(
      fetch('https://api.wheretheiss.at/v1/satellites/25544')
        .then(r => r.json())
    )
  ),
  $.map(data => ({
    ts: Number(data.timestamp ?? 0),
    lat: Number(data.latitude ?? NaN),
    lon: Number(data.longitude ?? NaN),
    altKm: Number(data.altitude ?? NaN),
    velKph: Number(data.velocity ?? NaN),
  })),
  $.shareReplay({ bufferSize: 1, refCount: true })
);

Derived Reactive Data

Next we derive a stream that only emits when the ISS position meaningfully changes.

const geoInputs$ = issRaw$.pipe(
  $.map(x => ({
    latQ: Math.round(x.lat * 100) / 100,
    lonQ: Math.round(x.lon * 100) / 100,
  })),
  $.distinctUntilChanged(
    (a, b) => a.latQ === b.latQ && a.lonQ === b.lonQ
  )
);

This prevents unnecessary recomputation.


The Reactive Model

const model = {
  iss: issRaw$,
  geo: geoInputs$,

  heartbeat: 0,
  expensiveRuns: 0,

  // Expensive computation
  expensiveGeoScore(lat, lon) {
    model.expensiveRuns++;

    let acc = 0;
    for (let i = 0; i  {
  model.heartbeat++;
}, 5000);
  • Enter fullscreen mode
  • Exit fullscreen mode

This does not trigger the expensive computation.
Why? Because the expression only depends on:

  • geo.latQ
  • geo.lonQ

rs‑x tracks these dependencies automatically.


Why This Matters

In many systems you need to manually manage recomputation:

  • useMemo
  • useEffect
  • Dependency arrays
  • Caching
  • Manual optimization

With rs‑x the rule is simple: describe your data and its relationships.
The runtime builds a reactive dependency graph and recomputes only what is required.


The Mental Model

Think of it like a spreadsheet. If cell A1 changes:

  • only cells that depend on A1 update
  • unrelated cells remain untouched

rs‑x brings this model to JavaScript expressions.


The Result

The demo creates a reactive computation graph that:

  • handles async streams
  • tracks dependencies automatically
  • avoids unnecessary recomputation
  • keeps code declarative and simple

No async orchestration.
No manual dependency tracking.
Just describe the data.


Support the Project

If you like rs‑x, consider supporting the project:

GitHub Sponsors – robert‑sanders‑software‑ontwikkeling

It helps me continue building open‑source tools for developers.


Tags

javascript #reactiveprogramming #rxjs #opensource #webdevelopment

0 views
Back to Blog

Related posts

Read more »