npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-on-fire

v1.0.2

Published

React hooks and helpers for Firebase (Firestore, Auth, Storage, FCM)

Readme

react-on-fire

react-on-fire is a React library for Firebase: Firestore (documents, collections, queries, aggregates, batch ops), Authentication (email, social, phone, anonymous, profile sync with Firestore), Storage (uploads, downloads, folders), Cloud Messaging (web FCM token + foreground messages), plus small utilities.

It is meant to be used inside a React app that already uses Firebase JS SDK v12+.

Repository: github.com/moFUNCTION/React-on-Fire


Requirements

  • Node 18+ (recommended for tooling)
  • React 18 or 19
  • Firebase ^12 (installed as a dependency of this package; your app should use a compatible version)

Installation

npm install react-on-fire

Quick start

Wrap your app with FirebaseProvider. It initializes the Firebase app, Auth, Firestore, Storage, Realtime Database, Analytics, and nests AuthProvider for user state tied to a Firestore users collection.

import { FirebaseProvider } from "react-on-fire";
import type { FirebaseOptions } from "firebase/app";

const firebaseConfig: FirebaseOptions = {
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
  measurementId: "...",
};

export function App() {
  return (
    <FirebaseProvider
      config={firebaseConfig}
      usersCollectionName="Users"
    >
      <MainRoutes />
    </FirebaseProvider>
  );
}
  • usersCollectionName (optional): Firestore collection for user profile documents (default "Users"). Used by auth/profile flows.

Read Firebase clients anywhere:

import { useConfigProvider, useFirebaseAuth } from "react-on-fire";

function Example() {
  const { app, auth, firestore, storage } = useConfigProvider();
  const authContext = useFirebaseAuth(); // from AuthProvider
  return null;
}

Package layout and imports

You can import everything from the root or use subpaths for clearer boundaries and tree-shaking.

| Subpath | Purpose | |--------|---------| | react-on-fire | All exports from the main barrel (see index.ts) | | react-on-fire/provider | FirebaseProvider, AuthProvider, useConfigProvider, useFirebaseAuth | | react-on-fire/firestore | Firestore classes, hooks, types | | react-on-fire/auth | useAuth, auth action hooks, types | | react-on-fire/storage | StorageHandler, UploadFiles, storage hooks, types | | react-on-fire/messaging | FCM hook + optional Cloud Functions helpers | | react-on-fire/common | isFirestoreValue, getFirebaseErrorMessage, FirebaseLocale | | react-on-fire/utilities | useServerTime |

Example — subpaths:

import { useDocument } from "react-on-fire/firestore";
import { useAuth } from "react-on-fire/auth";
import { FirebaseProvider } from "react-on-fire/provider";

1. Provider module

FirebaseProvider

Initializes Firebase and exposes useConfigProvider() with:

  • app, analytics, auth, firestore, google_auth, storage, realtimeDb

AuthProvider / useFirebaseAuth

FirebaseProvider already wraps your app with AuthProvider. useFirebaseAuth() returns the same object as useAuth (UseAuthReturn): user, loading, error, isAuthenticated, and all auth methods — but it reads from React context, so it only works under AuthProvider.

import { useFirebaseAuth } from "react-on-fire";

function ProfileBadge() {
  const { user, loading, isAuthenticated } = useFirebaseAuth();
  if (loading) return null;
  return <span>{isAuthenticated ? user?.displayName ?? user?.email : "Guest"}</span>;
}

Prefer useFirebaseAuth in most UI code so everything goes through the provider. Use useAuth({ usersCollectionName }) only if you mount a separate AuthProvider yourself.


2. Firestore module

Firestore code is built around Document and CollectionHandler classes plus many React hooks. Most hooks use useConfigProvider() and require the provider above.

Document operations — useDocumentOperations

Full CRUD and utilities for one document.

import { useDocumentOperations } from "react-on-fire/firestore";

function EditUser({ userId }: { userId: string }) {
  const {
    getDocument,
    updateDocument,
    loading,
    error,
  } = useDocumentOperations({
    collectionName: "users",
    documentId: userId,
    onError: (e) => console.error(e),
  });

  const save = async () => {
    await getDocument();
    await updateDocument({ displayName: "Ada" });
  };

  return (
    <button type="button" onClick={save} disabled={loading}>
      {error ? String(error) : "Save"}
    </button>
  );
}

Read document — useDocument

One-shot fetch or live subscription.

import { useDocument } from "react-on-fire/firestore";

function ProductCard({ id }: { id: string | null }) {
  const { data, loading, error, refetch } = useDocument({
    collectionName: "products",
    documentId: id,
    subscribe: true,
    enabled: !!id,
  });

  if (loading) return <p>Loading…</p>;
  if (error) return <p>{error.message}</p>;
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

Realtime snapshot — useDocumentSnapshot

Listener-focused API for a single document (always onSnapshot-style).

import { useDocumentSnapshot } from "react-on-fire/firestore";

function LiveCounter({ chatId }: { chatId: string | null }) {
  const { data, loading, error } = useDocumentSnapshot({
    collectionName: "chats",
    documentId: chatId,
    enabled: !!chatId,
  });
  return <div>{loading ? "…" : data?.messageCount ?? 0}</div>;
}

Pagination — useCollectionWithPagination

Cursor-based pages with optional realtime snapshots. Configure filters with whereQueries and sort with orderByQueries (types from CollectionHandler).

import { useCollectionWithPagination } from "react-on-fire/firestore";

function OrderList() {
  const {
    data,
    loading,
    error,
    page,
    pagesCount,
    handleGetNextPage,
    handleGetPreviousPage,
    isDisabledNext,
    isDisabledPrev,
    handleRender,
    count,
  } = useCollectionWithPagination({
    collectionName: "orders",
    pageSize: 20,
    orderByQueries: [{ field: "createdAt", direction: "desc" }],
    isRealtime: false,
  });

  return (
    <div>
      <button type="button" onClick={() => void handleRender()}>Refresh</button>
      {error && <p>{error}</p>}
      <ul>
        {data.map((row) => (
          <li key={row.id}>{JSON.stringify(row.data)}</li>
        ))}
      </ul>
      <p>
        Page {page + 1}
        {pagesCount > 0 ? ` / ${pagesCount}` : ""}
        {count.count > 0 ? ` — ${count.count} docs` : ""}
      </p>
      <button type="button" onClick={() => void handleGetPreviousPage()} disabled={isDisabledPrev}>
        Previous
      </button>
      <button type="button" onClick={() => void handleGetNextPage()} disabled={isDisabledNext}>
        Next
      </button>
    </div>
  );
}

Aggregates — useCollectionAggregates

Pass an aggregations array (AggregationConfig[]) for count / sum / average over the collection, with optional whereQueries and isRealtime.

import { useCollectionAggregates } from "react-on-fire/firestore";

function Stats() {
  const { data, loading, error } = useCollectionAggregates({
    collectionName: "orders",
    aggregations: [
      { type: "count", key: "total" },
      { type: "sum", field: "amount", key: "revenue" },
    ],
    whereQueries: [{ field: "status", operator: "==", value: "paid" }],
    isRealtime: false,
  });

  if (loading) return null;
  if (error) return <p>{error.message}</p>;
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

Batch writes — useBatchUpdate, useBatchDelete, useBatchCreate

Each hook is scoped to one collectionName and exposes an async function (batchUpdate, batchDelete, or batchCreate) plus loading / error / reset.

import { useBatchUpdate } from "react-on-fire/firestore";

function BulkDeactivate({ ids }: { ids: string[] }) {
  const { batchUpdate, loading } = useBatchUpdate({
    collectionName: "users",
  });

  const run = async () => {
    await batchUpdate(
      ids.map((docId) => ({ docId, data: { active: false } })),
    );
  };

  return (
    <button type="button" onClick={() => void run()} disabled={loading}>
      Deactivate all
    </button>
  );
}

Search / query helpers

Hooks such as useSearchByField, useSearchByPrefix, useAdvancedSearch, useGenericQuery, useGetDistinctValues, useExportCollectionAsJSON, etc., wrap CollectionHandler for common query patterns. Import from react-on-fire/firestore and pass collection name + filter options as required by each hook.

Classes — Document, CollectionHandler

Use directly when not inside a hook (e.g. server actions are not applicable here—but usable from non-React modules with a Firestore instance):

import { CollectionHandler, Document } from "react-on-fire/firestore";
import { useConfigProvider } from "react-on-fire/provider";

function LowLevel() {
  const { firestore } = useConfigProvider();
  const handler = new CollectionHandler(firestore, "items");
  return null;
}

More detail: see docs/FIRESTORE.md.


3. Auth module

useAuth

Primary hook: auth state plus email/social/phone/anonymous flows, profile and password helpers. Requires Firebase from FirebaseProvider (useConfigProvider is used internally).

import { useAuth } from "react-on-fire/auth";

function LoginPage() {
  const auth = useAuth();

  if (auth.loading) return <p>Loading…</p>;

  const onEmailLogin = async () => {
    await auth.loginWithEmail("[email protected]", "secret");
  };

  const onGoogle = async () => {
    await auth.loginWithGoogle({ saveUserGeo: true });
  };

  return (
    <div>
      <button type="button" onClick={onEmailLogin}>Email login</button>
      <button type="button" onClick={onGoogle}>Google</button>
    </div>
  );
}

Typical methods include: createUserWithEmail, loginWithEmail, loginWithGoogle / Facebook / Twitter / Github, signInAnonymously, phone sendPhoneCode / verifyPhoneCode, logout, updatePassword, sendPasswordReset, updateDocData, linkProvider, and more (see UseAuthReturn in types).

Auth action links (password reset, verify email, recover email)

useAuthActionParams takes a URLSearchParams instance (from the current URL or your router). For reset-password links, call verifyCode when the page loads, then resetPassword(newPassword) when the user submits the form.

import { useEffect, useMemo } from "react";
import {
  useAuthActionParams,
  useAuthActionResetPassword,
  isSupportedAuthActionMode,
} from "react-on-fire/auth";

function ResetPasswordRoute() {
  const searchParams = useMemo(
    () => new URLSearchParams(window.location.search),
    [],
  );
  const params = useAuthActionParams(searchParams);
  const { verifyCode, resetPassword, state, email, error, clearError } =
    useAuthActionResetPassword(params.oobCode);

  useEffect(() => {
    if (params.mode === "resetPassword" && params.oobCode) {
      void verifyCode();
    }
  }, [params.mode, params.oobCode, verifyCode]);

  if (!isSupportedAuthActionMode(params.mode)) {
    return <p>Invalid or unsupported link</p>;
  }

  const busy = state === "validating" || state === "submitting";

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        const pwd = new FormData(e.currentTarget).get("p") as string;
        void resetPassword(pwd);
      }}
    >
      {email && <p>Account: {email}</p>}
      {error && (
        <p>
          {error.message_en.message}
          <button type="button" onClick={clearError}>Dismiss</button>
        </p>
      )}
      <input name="p" type="password" autoComplete="new-password" />
      <button type="submit" disabled={busy || state !== "valid"}>
        Update password
      </button>
    </form>
  );
}

More detail: docs/AUTH.md.


4. Storage module

Hooks (recommended in components)

import {
  useFirebaseStorage,
  useStorageHandler,
  useUploadFiles,
} from "react-on-fire/storage";

function Uploader() {
  const storage = useFirebaseStorage();
  const handler = useStorageHandler("uploads");
  const uploadFiles = useUploadFiles();

  const onFiles = async (files: FileList | null) => {
    if (!files?.length) return;
    await uploadFiles({ files: Array.from(files), StoragePath: "docs" });
  };

  return <input type="file" multiple onChange={(e) => void onFiles(e.target.files)} />;
}

StorageHandler class

Imperative API for uploads, downloads, listing, delete, metadata, batch ops, etc.

import { StorageHandler } from "react-on-fire/storage";
import { useConfigProvider } from "react-on-fire/provider";

function ManualUpload({ file }: { file: File }) {
  const { storage } = useConfigProvider();
  const handler = new StorageHandler({ storage, basePath: "public" });

  const run = async () => {
    const info = await handler.uploadFile("images/hero.png", file);
    console.log(info.downloadURL);
  };

  return <button type="button" onClick={run}>Upload</button>;
}

More detail: docs/STORAGE.md.


5. Cloud Messaging module

useFirebaseMessaging

Web FCM: service worker, permission, token, foreground onMessage.

import { useFirebaseMessaging, useConfigProvider } from "react-on-fire";

function FcmRegistrar() {
  const { app } = useConfigProvider();

  useFirebaseMessaging({
    app,
    vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY,
    enabled: true,
    serviceWorkerPath: "/firebase-messaging-sw.js",
    onForegroundMessage: (payload) => {
      console.log("Foreground notification", payload);
    },
    onToken: async (token) => {
      // e.g. persist token in Firestore for targeted sends
      console.log(token);
    },
  });

  return null;
}

You must host firebase-messaging-sw.js at the origin root and use HTTPS in production.

Callable helpers

callSubscribeFcmTopics, Callables type exports — see docs/FIREBASE_MESSAGING.md and Messaging/callables.ts (wired to your Cloud Functions names).


6. Common module

getFirebaseErrorMessage

Maps Firebase error codes to localized messages (supports Arabic locale helpers — see FirebaseLocale).

import { getFirebaseErrorMessage } from "react-on-fire/common";

try {
  // firebase call
} catch (e) {
  console.log(getFirebaseErrorMessage(e, "en"));
}

isFirestoreValue

Validates values suitable for Firestore writes.

import { isFirestoreValue } from "react-on-fire/common";

if (isFirestoreValue(payload)) {
  // safe to pass to Firestore
}

7. Utilities

useServerTime

Subscribes to Realtime Database .info/serverTimeOffset (via FirebaseProvider) and returns an estimated Date for the server clock, updated when offset changes.

import { useServerTime } from "react-on-fire/utilities";

function ServerClock() {
  const serverTime = useServerTime();
  return <time dateTime={serverTime.toISOString()}>{serverTime.toLocaleString()}</time>;
}

TypeScript

Types ship with the package (dist/*.d.ts). Enable strict mode in your app for best inference.


Building and publishing (maintainers)

From this folder (react-fire/):

npm install
npm run build
npm publish --access public
  • prepublishOnly runs npm run build automatically before publish.
  • Published artifacts: dist/ (ESM + declarations), plus README and LICENSE.

Before the first publish, confirm the package name react-on-fire is available on npm or change the "name" field in package.json.


License

ISC — see LICENSE.


Further reading in this repo