Documentation
Complete reference for the Firebase client adapter, browser models, and realtime React hooks.
@dharayush7/fireclass-react binds Fireclass to the modular Firebase client SDK
and adds realtime collection and document hooks.
npm install @dharayush7/fireclass-react firebase react class-validator class-transformer reflect-metadata| Export | Kind | Purpose |
|---|---|---|
createFireclass | Function | Bind models and hooks to client Firestore. |
Fireclass | Type | Return type of createFireclass. |
ClientAdapter | Class | Client SDK implementation of CRUD, queries, and realtime. |
RealtimeAdapter | Interface | Extended adapter contract required by hooks. |
makeHooks | Function | Build hooks from a custom realtime adapter. |
ModelLike | Interface | Minimal model shape with optional id. |
ModelCtor | Type | Constructor accepted by the hooks. |
QueryResult | Interface | useQuery state. |
DocResult | Interface | useDoc state. |
The package also re-exports every fireclass-core value and
type.
function createFireclass(db: Firestore): {
BaseModel: BaseModelClass;
adapter: ClientAdapter;
useQuery: typeof useQuery;
useDoc: typeof useDoc;
};
type Fireclass = ReturnType<typeof createFireclass>;Creates one ClientAdapter, its bound BaseModel, and hooks bound to the same
adapter.
import "reflect-metadata";
import { createFireclass } from "@dharayush7/fireclass-react";
import { db } from "./firebase";
export const {
BaseModel,
adapter,
useQuery,
useDoc,
} = createFireclass(db);Use one shared binding so every model and hook talks to the same Firebase app.
function useQuery<T extends ModelLike>(
model: ModelCtor<T>,
options?: QueryOptions<T>,
): QueryResult<T>;
interface QueryResult<T> {
data: T[];
loading: boolean;
error: Error | null;
}Subscribes to a live Firestore query and hydrates snapshots as model instances.
function TodoList() {
const { data, loading, error } = useQuery(Todo, {
where: { done: { equals: false } },
orderBy: { title: "asc" },
});
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
return data.map((todo) => <TodoRow key={todo.id} todo={todo} />);
}| Event | State |
|---|---|
| Initial render or resubscribe | Previous data, loading: true, error: null |
| Snapshot | Hydrated data, loading: false, error: null |
| Subscription error | data: [], loading: false, received error |
| Unmount or dependency change | Active listener unsubscribes |
The hook requires collection metadata and throws MissingCollectionError for an
undecorated model.
It derives a normalized query string so equivalent inline option objects do not cause repeated subscriptions.
Realtime query values must serialize cleanly
useQuery currently stabilizes its query through JSON.stringify and
JSON.parse. Non-JSON query values such as Date, Firestore references, or
DocumentSnapshots do not retain their runtime identity. Use JSON-native filter
and cursor values with the hook in this release.
function useDoc<T extends ModelLike>(
model: ModelCtor<T>,
id: string | undefined,
): DocResult<T>;
interface DocResult<T> {
data: T | null;
loading: boolean;
error: Error | null;
}Subscribes to one document and hydrates it as a model instance.
function TodoDetails({ id }: { id?: string }) {
const { data: todo, loading, error } = useDoc(Todo, id);
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!todo) return <NotFound />;
return <h1>{todo.title}</h1>;
}Passing undefined skips subscription and returns
{ data: null, loading: false, error: null }. A missing document also resolves
to data: null after the snapshot arrives.
On a subscription error, state becomes
{ data: null, loading: false, error }. The listener unsubscribes on id or model
change and on unmount.
interface ModelLike {
id?: string;
}
type ModelCtor<T extends ModelLike> = new (
data?: Partial<T>,
) => T;These are the minimum structural requirements for realtime hydration. A class
does not need to extend BaseModel to work with makeHooks, but it must carry
collection metadata and accept optional partial constructor data.
function makeHooks(adapter: RealtimeAdapter): {
useQuery: typeof useQuery;
useDoc: typeof useDoc;
};Advanced factory for custom adapters and isolated hook tests. Most applications
should use createFireclass.
const { useQuery, useDoc } = makeHooks(customRealtimeAdapter);Hook hydration calls adapter.convert when present, constructs the model, then
assigns the payload again so classes with minimal constructors still receive
snapshot fields.
interface RealtimeAdapter extends FirestoreAdapter {
subscribe(
collection: string,
spec: QuerySpec,
callback: (docs: DocSnapshot[]) => void,
onError?: (error: Error) => void,
): () => void;
subscribeDoc(
collection: string,
id: string,
callback: (data: Record<string, unknown> | null) => void,
onError?: (error: Error) => void,
): () => void;
}Both methods return an unsubscribe function. subscribe is required here even
though it is optional in the core adapter contract.
class ClientAdapter implements RealtimeAdapter {
constructor(db: Firestore);
}| Method | Result | Firebase client operation |
|---|---|---|
add(collection, data) | Promise<{ id: string }> | addDoc |
set(collection, id, data, options) | Promise<void> | setDoc with merge |
get(collection, id) | Promise<Record<string, unknown> | null> | getDoc |
query(collection, spec) | Promise<DocSnapshot[]> | getDocs |
delete(collection, id) | Promise<void> | deleteDoc |
batchDelete(collection, ids) | Promise<void> | Write batches of at most 500 deletes |
count(collection, spec) | Promise<number> | getCountFromServer |
subscribe(collection, spec, callback, onError?) | () => void | Query onSnapshot |
subscribeDoc(collection, id, callback, onError?) | () => void | Document onSnapshot |
convert(data) | Record<string, unknown> | Recursive Timestamp-to-Date conversion |
Direct adapter callbacks receive raw snapshot data. Fireclass model and hook
hydration applies convert before constructing instances.
Client writes and reads execute as the signed-in Firebase user. Fireclass does
not replace Firestore Security Rules, authentication, App Check, or index
configuration. Firebase SDK errors are exposed through hook error state or
rejected model promises without wrapping.