Reactive Data Without the Async Headaches
Source: Dev.to
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.latQgeo.lonQ
rs‑x tracks these dependencies automatically.
Why This Matters
In many systems you need to manually manage recomputation:
useMemouseEffect- 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
