I recently came across MkDocs-Material by Martin Donath, a fantastic open-source project with over 22k GitHub stars.
It’s an incredible contribution to the community, making documentation hosting effortless.
While exploring it, I got curious about how such a large project achieves reactiveness.
The stack is mostly HTML, SCSS, Preact, RxJS, and a few workers, and I saw this as the perfect opportunity to dive into RxJS—especially how it utilizes Observables and other advanced patterns.
So, let’s break down RxJS from the ground up and see what makes it tick!
What is RxJS?
RxJS (Reactive Extensions for JavaScript) is a library for composing asynchronous and event-based programs using Observables.
Think of Observables as data streams you can listen to, transform, combine, and control with precision.
In simpler terms: RxJS helps you manage async data like a pro.
Why Should You Care?
Here’s why RxJS is worth your attention:
- Declarative Approach: Focus on what to do with data, not how to manage it.
- Powerful Operators: Transform, filter, and combine streams with ease.
- Versatile: Perfect for handling user interactions, HTTP requests, WebSockets, and more.
Getting Started
First, install RxJS with npm:
npm install rxjs
Creating Observables
1. From Scratch
You can create an observable using new Observable()
.
Inside it, you define what to send to subscribers using observer.next()
. This can be literally anything—a string, an object, even your to-do list (though maybe don’t do that).
To get things rolling, just call subscribe()
, which makes the observable start firing off those values.
Here’s a quick example:
import { Observable } from 'rxjs';
const customObservable = new Observable(observer => {
observer.next('Hi');
observer.next('Mom');
observer.complete();
});
customObservable.subscribe({
next: value => console.log(value),
complete: () => console.log(`I'm Done!`)
});
// Output:
// Hi
// Mom
// I'm Done!
Boom! Values are sent, received, and when there’s nothing left to say, complete()
wraps it up like a polite email sign-off.
2. From DOM Events
Want to react to user clicks?
Just use fromEvent()
.
Pass in the DOM element and the event you care about—like click
.
import { fromEvent } from 'rxjs';
const button = document.getElementById('myButton');
const clicks$ = fromEvent(button, 'click');
clicks$.subscribe(() => console.log('Button clicked!'));
Now, every time someone clicks the button, it logs “Button clicked!” Simple, right?
You could even hook this up to rage-click counters.
3. From Promises
Got a promise?
You can turn it into an observable with from()
.
This is super handy when dealing with promise-based libraries.
import { from } from 'rxjs';
const promise = new Promise(resolve => setTimeout(() => resolve('Resolved!'), 1000));
const observableFromPromise = from(promise);
observableFromPromise.subscribe(value => console.log(value));
// Converting back to a promise
observableFromPromise.toPromise().then(console.log);
// Output
// Resolved.
This simulates an API call (aka: fake waiting).
After one second, it logs “Resolved!” Oh, and if you ever miss promises that much, you can flip it back with toPromise()
.
4. Static Values
Need to turn random data into an observable?
Use of()
. It doesn’t care what you throw at it—numbers, strings, booleans, objects, your grocery list…
import { of } from 'rxjs';
const staticValues$ = of(1, 'RxJS', true, { key: 'value' });
staticValues$.subscribe(value => console.log(value));
// Output:
// 1
// RxJS
// true
// { key: 'value' }
Basically, anything can be part of a stream.
Yes, anything. Even your existential crisis.
5. Timers and Intervals
If you need to fire events after a delay or at regular intervals, RxJS has your back:
- Timers trigger once after a set delay.
- Intervals keep firing like an overenthusiastic alarm clock.
import { timer, interval } from 'rxjs';
// Emits once after 2 seconds
timer(2000).subscribe(() => console.log('Timer fired!'));
// Emits every second
interval(1000).subscribe(count => console.log(`Count: ${count}`));
timer()
waits politely before saying anything, while interval()
just can’t stop talking—perfect for regular updates (or if you’re trying to annoy your console).
Wrapping Up
RxJS might feel overwhelming at first, but once you get the hang of it, you’ll wonder how you ever managed async code without it.
Start small, experiment, and soon you’ll be chaining Observables like a boss.
This is just the beginning(observable)—there’s so much more to explore in RxJS, from advanced operators to real-world patterns.
I’ll be sharing more learnings, so stick around/follow for more deep dives into RxJS and beyond! 🚀
Got questions about Observables or cool RxJS tricks? Drop them in the comments below!
Checkout others:
![lovestaco](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1002302%2F5233b7df-6ee3-46b2-b8d7-1fafe103e8a3.jpg)
How This SCSS Project Stays Organized Starting from a Map
Athreya aka Maneshwar ・ Dec 29 '24
While exploring mkdocs-material implementation, I've been learning how to adapt these techniques for LiveAPI, a product I've been passionately working on for quite a while.
With LiveAPI, you can quickly generate interactive API documentation that allows users to execute APIs directly from the browser.
If you’re tired of manually creating docs for your APIs, this tool might just make your life easier.
Top comments (0)