React Integration
Routier supports live React subscriptions through useQuery and one-time React 19 Suspense reads through Routier's Promise-based terminal methods.
⚛️ Interactive React Demo
See Routier's React integration in action with live examples of `useQuery`, live queries, and reactive updates.
Features
- Live Queries:
useQueryre-renders when subscribed data changes - Suspense Reads: React 19
use()readstoArrayAsync()and other Promise terminals - Type Safe: Discriminated hook state and inferred query result types
- Lifecycle Safe: Dependency-driven subscription cleanup
Choose a loading style
| Style | Behavior |
|---|---|
useQuery + .subscribe() | Initial result plus live updates; explicit pending/error/success state |
React 19 use() + <Suspense> | One result per stable Promise; boundary-based loading and errors through an error boundary |
Live-query quick start
import { useQuery } from "@routier/react";
import { useDataStore } from "./hooks/useDataStore";
function ProductsList() {
const dataStore = useDataStore(); // Must be memoized in useDataStore hook
const products = useQuery(
(callback) => dataStore.products.subscribe().toArray(callback),
[dataStore]
);
if (products.status === "pending") return <div>Loading...</div>;
if (products.status === "error") return <div>Error!</div>;
return (
<ul>
{products.status === "success" &&
products.data.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}Important: Your useDataStore hook must use useMemo or Context to keep the DataStore instance stable. Creating a new DataStore on every render recreates subscriptions continuously. See Best Practices for details.
Suspense quick start (React 19)
Use an async terminal and keep its Promise in a parent ref so the component that calls use() receives the same request on every retry:
import { Suspense, use, useRef } from "react";
import { useDataStore } from "./DexieStore"; // Your app's datastore hook/context
type AppDataStore = ReturnType<typeof useDataStore>;
type ProductsPromise = ReturnType<AppDataStore["products"]["toArrayAsync"]>;
function ProductsListContent({ request }: { request: ProductsPromise }) {
const products = use(request);
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
export function SuspenseProductsList() {
const store = useDataStore(); // Keep this instance stable (Context or useMemo).
const requestRef = useRef<ProductsPromise | null>(null);
// This component does not suspend, so the ref survives while the boundary
// renders its fallback and retries ProductsListContent.
requestRef.current ??= store.products.toArrayAsync();
return (
<Suspense fallback={<div>Loading products…</div>}>
<ProductsListContent request={requestRef.current} />
</Suspense>
);
}This performs a one-time read; it does not subscribe to later database changes. See the React Adapter for the complete comparison.
Installation
npm install @routier/react
# Install peer dependencies
npm install react react-domCore Concepts
useQuery Hook
The useQuery hook subscribes to Routier collections and returns loading, error, and success states:
const result = useQuery(
(callback) => collection.subscribe().toArray(callback),
[
/* dependencies */
]
);
// result.status: 'pending' | 'success' | 'error'
// result.loading: boolean
// result.error: Error | null
// result.data: T | undefinedAutomatic Updates
Queries automatically re-render when your data changes:
// Add a product
await dataStore.products.addAsync({ name: "New Product" });
await dataStore.saveChangesAsync();
// Component automatically re-renders with new data!Type Safety
TypeScript knows exactly what state your component is in:
if (products.status === "success") {
// TypeScript knows products.data is defined here
console.log(products.data); // ✅ Safe
}Related Topics
- React Adapter - Side-by-side live-query and Suspense examples
- React Hooks - Detailed
useQuery, cleanup, and Suspense guide - Best Practices - Datastore lifetime and subscription patterns
Concepts You'll Need
- Live Queries - Understanding live queries in depth
- Optimistic Replication - Fast reads with memory replication
- State Management - Managing application state