qwik-observable-hooks
v0.1.1
Published
Qwik hooks for RxJS Observables. Simple, flexible, testable and performant.
Readme
Qwik Observable Hooks ⚡️
Qwik hooks for RxJS Observables. Simple, flexible, testable and performant.
- Seamless integration of Qwik tasks/signals and RxJS streams.
- Observables →
Signals (useObservableValue,useObservableEagerValue). - Qwik events → Observables with
QRL-powered dispatcher callbacks. - Hydration-aware pipeline repair powered by Qwik tasks and
useVisibleTask$. - Fine-grained subscription hooks (
useSubscription) for pure side-effects.
- Observables →
- Full-powered RxJS. Do whatever you want with Observables. No limitation nor compromise.
- SSR & resumability safe. Observables are
NoSerializeand resubscribe after render commits; state and emitted values stay serializable and resume from server to client. - Tiny and fast. No runtime dependencies beyond RxJS and Qwik; marked as
sideEffects: false. - Fully tested helpers to keep your marble tests happy.
- Compatible with RxJS 9.0.0-beta.0 and every rendering surface that Qwik supports (SSR, SPA, islands, edge). See
docs/rxjs-9.md.
Why?
Qwik added resumability for reusing stateful logic without hydration cost while RxJS offers a powerful way to encapsulate sync/async logic.
Testing Observables with marbles is straightforward. By combining Qwik's signal model with RxJS Observables, we can author reactive components that are lazy by default, streaming server-rendered HTML without pulling large bundles to the client.
With qwik-observable-hooks you can create rich, resumable components with ease.
What It Is Not
This library is not a replacement for state management libraries but a bridge. Use signals, contexts, or stores wherever they make sense, and only bring RxJS to the parts of the tree that truly benefit from reactive streams.
Using this library does not mean every value should become an Observable. Stick to regular Qwik primitives for simple state and reach for these hooks when streams let you model reality better.
At First Glance
import { component$, $ } from "@qwik.dev/core";
import { timer } from "rxjs";
import { switchMap, mapTo, startWith } from "rxjs/operators";
import { useObservableValue } from "qwik-observable-hooks";
const App = component$(() => {
const [isTyping, updateIsTyping] = useObservableValue(
$((event$) =>
event$.pipe(
switchMap(() => timer(1000).pipe(mapTo(false), startWith(true))),
),
),
false,
);
return (
<div>
<input type="text" onKeyDown$={(event) => updateIsTyping(event)} />
<p>{isTyping.value ? "Good you are typing." : "Why stop typing?"}</p>
<button onClick$={(event) => updateIsTyping(event)}>Mock Key</button>
</div>
);
});Logic stays pure and can be tested like an Epic in redux-observable. Every callback is a QRL, so the whole thing remains lazy-load friendly.
Installation
bun
bun add qwik-observable-hooks rxjsnpm
npm install qwik-observable-hooks rxjspnpm
pnpm add qwik-observable-hooks rxjsyarn
yarn add qwik-observable-hooks rxjsUsage
Read the docs at https://qwik-observable-hooks.js.org (our VitePress instance lives there).
Here is how the API is structured which might help you decide which hook to reach for:

Examples live in the root /docs site (npm run docs:dev). Share more recipes with us!
Note that there are also some useful helpers for common use cases to reduce garbage collection and boilerplate.
