All Projects → cvara → rxdb-hooks

cvara / rxdb-hooks

Licence: MIT License
React hooks for integrating with RxDB

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to rxdb-hooks

MERN-BUS-APP
This is a MFRP (My first Real Project) assigned to me during my internship at Cognizant. Made with MERN Stack technology.
Stars: ✭ 92 (+61.4%)
Mutual labels:  react-hooks
window-scroll-position
React hook for Window scroll position
Stars: ✭ 81 (+42.11%)
Mutual labels:  react-hooks
atomic-state
A decentralized state management library for React
Stars: ✭ 54 (-5.26%)
Mutual labels:  react-hooks
react-sendbird-messenger
ReactJS (React-router-dom v6 + Antdesign + Firebase + Sendbird + Sentry) codebase containing real world examples (CRUD, auth, advanced patterns, etc).
Stars: ✭ 39 (-31.58%)
Mutual labels:  react-hooks
Fakeflix
Not the usual clone that you can find on the web.
Stars: ✭ 4,429 (+7670.18%)
Mutual labels:  react-hooks
Facebook-Messenger
This is a Facebook Messenger clone.You can comminicate to other at realtime.Used ReactJS, Material UI, Firebase, Firestore Database
Stars: ✭ 18 (-68.42%)
Mutual labels:  react-hooks
react-abac
Attribute Based Access Control for React
Stars: ✭ 54 (-5.26%)
Mutual labels:  react-hooks
how-react-hooks-work
Understand how React-hook really behaves, once and for all!
Stars: ✭ 73 (+28.07%)
Mutual labels:  react-hooks
platyplus
Low-code, offline-first apps with Hasura
Stars: ✭ 22 (-61.4%)
Mutual labels:  rxdb
react-social-network
react social network
Stars: ✭ 13 (-77.19%)
Mutual labels:  react-hooks
react-hooks-file-upload
React Hooks File Upload example with Progress Bar using Axios, Bootstrap
Stars: ✭ 30 (-47.37%)
Mutual labels:  react-hooks
learn-react-typescript
Learning React contents with TypeScript (Hooks, Redux)
Stars: ✭ 15 (-73.68%)
Mutual labels:  react-hooks
react-emotion-multi-step-form
React multi-step form library with Emotion styling
Stars: ✭ 25 (-56.14%)
Mutual labels:  react-hooks
react-europe-2019
Slides and demo app from my keynote
Stars: ✭ 29 (-49.12%)
Mutual labels:  react-hooks
react-admin-nest
React和Ant Design和 Nest.js 和 Mysql 构建的后台通用管理系统。持续更新。
Stars: ✭ 123 (+115.79%)
Mutual labels:  react-hooks
react
🎣 React hooks & components on top of ocean.js
Stars: ✭ 27 (-52.63%)
Mutual labels:  react-hooks
react-change-highlight
✨ a react component to highlight changes constantly ⚡️
Stars: ✭ 79 (+38.6%)
Mutual labels:  react-hooks
react-hook-form-auto
Automatic form generation using ReactHookForm
Stars: ✭ 45 (-21.05%)
Mutual labels:  react-hooks
frontegg-react
Frontegg-React is pre-built Component for faster and simpler integration with Frontegg services.
Stars: ✭ 15 (-73.68%)
Mutual labels:  react-hooks
MetFlix
A Movie app demo. Like NetFlix ❤️
Stars: ✭ 50 (-12.28%)
Mutual labels:  react-hooks

rxdb-hooks

npm version downloads

Table of Contents

Click to expand

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(() => {
    // Notice that RxDB instantiation is asynchronous;
    // until db becomes available consumer hooks that depend
    // on it will still work, absorbing the delay by
    // setting their state to isFetching:true
    const initDB = async () => {
      const _db = await initialize();
      setDb(_db);
    };
    initDB();
  }, []);

  // Provide RxDB instance; hooks can now be used
  // within the context of the Provider
  return (
    <Provider db={db}>
      <App />
    </Provider>
  );
};

Consumer.jsx:

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

const Consumer = () => {
  const queryConstructor = collection =>
    collection
      .find()
      .where('affiliation')
      .equals('jedi');

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

  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',
          },
          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
4.x 10.x, 11.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

API

Provider

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

Props

Property Type Required Default Description
db RxDatabase * - the RxDatabase instance to consume data from
idAttribute string - "_id" used by useRxDocument when querying for single documents

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 Required Default Description
pageSize number - - enables pagination & defines page limit
pagination "Traditional" | "Infinite" - "Traditional" 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.
json boolean - false when true resulting documents will be converted to plain JavaScript objects; equivalent to manually calling .toJSON() on each RxDocument

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()
  .where('affiliation')
  .equals('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')
);

useRxDocument

Convenience hook for fetching a single document from a collection.

function useRxDocument<T>(
	collectionName: string,
	id?: string | number,
	options?: UseRxDocumentOptions
): RxDocumentRet<T>

id

The id of the document

options

Option Type Required Default Description
idAttribute string - "_id" enables overriding the id attribute; has precedence over idAttribute set by the <Provider />
json boolean - false converts resulting RxDocument to plain javascript object

Example

const { result: Yoda } = useRxDocument('characters', 'Yoda', {
  idAttribute: 'name',
});

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 collection = useRxCollection('characters');

const query = useMemo(
  () =>
    collection
      .find()
      .where('affiliation')
      .equals(affiliation), // 👈 could come from component props
  [collection, affiliation]
);

const { result } = useRxQuery(query);

Same goes for useRxData and the queryConstructor function:

const queryConstructor = useCallback(
  collection =>
    collection
      .find()
      .where('affiliation')
      .equals(affiliation), // 👈 could come from component props
  [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)

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

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].