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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rxdb-hooks

v5.0.2

Published

React hooks for integrating with RxDB

Downloads

21,115

Readme

rxdb-hooks

Table of Contents

About

A set of simple hooks for integrating a React application with RxDB.

Nothing fancy, just conveniently handles common use cases such as:

  • subscribing to query observables and translating results into React state
  • cleaning up after subscriptions where necessary
  • paginating results
  • maintaining useful state information (i.e. data fetching or data exhaustion during pagination)
  • lazily creating or destroying collections

Installation

# using npm
npm install rxdb-hooks

# using yarn
yarn add rxdb-hooks

Example

Root.jsx:

import React, { useEffect } from 'react';
import { Provider } from 'rxdb-hooks';
import initialize from './initialize';

const Root = () => {
  const [db, setDb] = useState();

  useEffect(() => {
    // RxDB instantiation can be asynchronous
    initialize().then(setDb);
  }, []);

  // Until db becomes available, consumer hooks that
  // depend on it will still work, absorbing the delay
  // by setting their state to isFetching:true
  return (
    <Provider db={db}>
      <App />
    </Provider>
  );
};

Consumer.jsx:

import React from 'react';
import { useRxData } from 'rxdb-hooks';

const Consumer = () => {
  const { result: characters, isFetching } = useRxData(
    // the collection to be queried
    'characters',
    // a function returning the query to be applied
    collection =>
      collection.find({
        selector: {
          affiliation: 'jedi',
        },
      })
  );

  if (isFetching) {
    return 'loading characters...';
  }

  return (
    <ul>
      {characters.map((character, idx) => (
        <li key={idx}>{character.name}</li>
      ))}
    </ul>
  );
};

initialize.js:

const initialize = async () => {
  // create RxDB
  const db = await createRxDatabase({
    name: 'test_database',
  });

  // create a collection
  const collection = await db.addCollections({
    characters: {
      schema: {
        title: 'characters',
        version: 0,
        type: 'object',
        primaryKey: 'id',
        properties: {
          id: {
            type: 'string',
            maxLength: 100,
          },
          name: {
            type: 'string',
          },
        },
      },
    },
  });

  // maybe sync collection to a remote
  // ...

  return db;
};

Compatibility with RxDB

The core API of rxdb-hooks remains largely the same across all major versions beyond 1.x, however some parts of the internal implementation (most notably the plugin) differ based on the version of rxdb we need to target *. Please use the appropriate version of rxdb-hooks as per this table:

| rxdb-hooks version | targeted RxDB version | | ------------------ | ---------------------- | | 5.x | 14.x | | 4.1.x | 13.x | | 4.0.x | 10.x, 11.x, 12.x | | 3.x | 9.x | | 1.x, 2.x | 8.x |

* Versions 7.x of RxDB and below have not been tested and are not guaranteed to work with rxdb-hooks

Migration Guide

4.x => 5.x

  • useRxDocument has been dropped; for fetching single documents simply use useRxQuery or useRxData
  • observing lazily created collection has become an opt-in feature that, if needed, has to be explicitly enabled by using the provided plugin. For more info see Lazy instantiation of RxDatabase & RxCollections

API

Provider

The <Provider /> makes the RxDatabase instance available to nested components and is required for all subsequent hooks to work.

Props

| Property | Type | Description | | -------- | ------------ | -------------------------------------------- | | db | RxDatabase | the RxDatabase instance to consume data from |

useRxDB

Returns the RxDatabase instance made available by the <Provider />

function useRxDB(): RxDatabase

Example

const db = useRxDB();

useRxCollection

Given a collection name returns an RxCollection instance, if found in RxDatabase.

function useRxCollection<T>(name: string): RxCollection<T> | null

Example

const collection = useRxCollection('characters');

useRxQuery

Subscribes to given RxQuery object providing query results and some helpful extra state variables.

function useRxQuery<T>(query: RxQuery, options?: UseRxQueryOptions): RxQueryResult<T>

options: UseRxQueryOptions

| Option | Type | Description | | ------------ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | pageSize | number | (optional) enables pagination & defines page limit | | pagination | "Traditional" \| "Infinite" | (optional) determines pagination mode: Traditional: results are split into pages, starts by rendering the first page and total pageCount is returned, allowing for requesting results of any specific page. Infinite: first page of results is rendered, allowing for gradually requesting more. Default: "Traditional" | | json | boolean | (optional) when true resulting documents will be converted to plain JavaScript objects; equivalent to manually calling .toJSON() on each RxDocument. Default: false |

result: RxQueryResult<T>

| Property | Type | Description | | ------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | result | T[] \| RxDocument<T>[] | the resulting array of objects or RxDocument instances, depending on json option | | isFetching | boolean | fetching state indicator | | currentPage | number | relevant in all pagination modes; holds number of current page | | isExhausted | boolean | relevant in Infinite pagination; flags result list as "exhausted", meaning all documents have been already fetched | | fetchMore | () => void | relevant in Infinite pagination; a function to be called by the consumer to request documents of the next page | | resetList | () => void | relevant in Infinite pagination; a function to be called by the consumer to reset paginated results | | pageCount | number | relevant in Traditional pagination; holds the total number of pages available | | fetchPage | (page: number) => void | relevant in Traditional pagination; a function to be called by the consumer to request results of a specific page |

Simple Example

const collection = useRxCollection('characters');

const query = collection.find().where('affiliation').equals('Jedi');

const { result } = useRxQuery(query);

Infinite Scroll Pagination Example

const collection = useRxCollection('characters');

const query = collection.find().where('affiliation').equals('Jedi');

const {
  result: characters,
  isFetching,
  fetchMore,
  isExhausted,
} = useRxQuery(query, {
  pageSize: 5,
  pagination: 'Infinite',
});

if (isFetching) {
  return 'Loading...';
}

return (
  <CharacterList>
    {characters.map((character, index) => (
      <Character character={character} key={index} />
    ))}
    {!isExhausted && <button onClick={fetchMore}>load more</button>}
  </CharacterList>
);

Traditional Pagination Example

const collection = useRxCollection('characters');

const query = collection.find({
  selector: {
    affiliation: 'jedi',
  },
});

const {
  result: characters,
  isFetching,
  fetchPage,
  pageCount,
} = useRxQuery(query, {
  pageSize: 5,
  pagination: 'Traditional',
});

if (isFetching) {
  return 'Loading...';
}

// render results and leverage pageCount to render page navigation
return (
  <div>
    <CharacterList>
      {characters.map((character, index) => (
        <Character character={character} key={index} />
      ))}
    </CharacterList>
    <div>
      {Array(pageCount)
        .fill()
        .map((x, i) => (
          <button
            onClick={() => {
              fetchPage(i + 1);
            }}
          >
            page {i + 1}
          </button>
        ))}
    </div>
  </div>
);

useRxData

Convenience wrapper around useRxQuery that expects a collection name & a query constructor function

function useRxData<T>(
	collectionName: string,
	queryConstructor: ((collection: RxCollection<T>) => RxQuery<T> | undefined) | undefined,
	options?: UseRxQueryOptions
): RxQueryResult<T>

Example

const { result } = useRxData('characters', collection =>
  collection.find().where('affiliation').equals('Jedi')
);

Recipes

Query and Query Constructor memoization

By design, useRxQuery will re-subscribe to query object whenever it changes, allowing for query criteria to be modified during component updates. For this reason, to avoid unnecessary re-subscriptions, query should be memoized (i.e. via react's useMemo):

const { affiliation } = props;
const collection = useRxCollection('characters');

const query = useMemo(
  () =>
    collection.find({
      selector: {
        affiliation,
      },
    }),
  [collection, affiliation]
);

const { result } = useRxQuery(query);

Same goes for useRxData and the queryConstructor function:

const { affiliation } = props;

const queryConstructor = useCallback(
  collection =>
    collection.find({
      selector: {
        affiliation,
      },
    }),
  [affiliation]
);

const { result } = useRxData('characters', queryConstructor);

Lazy instantiation of RxDatabase & RxCollections

All rxdb-hooks give you the ability to lazily instantiate the database and the collections within it. Initial delay until the above become available is absorbed by indicating the state as fetching (isFetching:true).

Since v5.0.0 of rxdb-hooks, observing newly created collections has become an opt-in feature that, if needed, has to be enabled via the provided observeNewCollections plugin:

import { addRxPlugin } from 'rxdb';
import { observeNewCollections } from 'rxdb-hooks';

addRxPlugin(observeNewCollections);

Adding the plugin makes it possible for all rxdb-hooks to pick up data from collections that are lazily added after the inital db initialization.

Also note that lazily instantiating the rxdb instance itself is supported out-of-the-box, the plugin only affects lazy collection creation.

Mutations

Performing mutations on data is possible through the APIs provided by RxDocument and RxCollection:

Example

const collection = useRxCollection('characters');

collection.upsert({
  name: 'Luke Skywalker',
  affiliation: 'Jedi',
});

LICENSE

MIT