Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cvara/rxdb-hooks
React hooks for integrating with RxDB
https://github.com/cvara/rxdb-hooks
react react-hooks react-rxdb rxdb use-rxdb
Last synced: 4 months ago
JSON representation
React hooks for integrating with RxDB
- Host: GitHub
- URL: https://github.com/cvara/rxdb-hooks
- Owner: cvara
- License: mit
- Created: 2020-03-02T15:29:17.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-08-15T22:24:33.000Z (over 1 year ago)
- Last Synced: 2024-04-15T07:23:20.802Z (10 months ago)
- Topics: react, react-hooks, react-rxdb, rxdb, use-rxdb
- Language: TypeScript
- Homepage:
- Size: 1.92 MB
- Stars: 123
- Watchers: 3
- Forks: 4
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# rxdb-hooks
#### React hooks for integrating with [RxDB](https://github.com/pubkey/rxdb)
## Table of Contents
Click to expand
- [About](#about)
- [Installation](#installation)
- [Example](#example)
- [Compatibility with RxDB](#compatibility-with-rxdb)
- [Migration Guide](#migration-guide)
- [API](#api)
- [`Provider`](#provider)
- [`useRxDB`](#userxdb)
- [`useRxCollection`](#userxcollection)
- [`useRxQuery`](#userxquery)
- [`useRxData`](#userxdata)
- [`useRxDocument`](#userxdocument)
- [Recipes](#recipes)
- [Query and Query Constructor memoization](#query-and-query-constructor-memoization)
- [Lazy instantiation of RxDatabase & RxCollections](#lazy-instantiation-of-rxdatabase--rxcollections)
- [Mutations](#mutations)
- [LICENSE](#license)## About
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
```bash
# using npm
npm install rxdb-hooks# using yarn
yarn add rxdb-hooks
```## Example
**Root.jsx**:
```javascript
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 (
);
};
```**Consumer.jsx**:
```javascript
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 (
- {character.name}
{characters.map((character, idx) => (
))}
);
};
```
**initialize.js**:
```javascript
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](src/plugins.ts)) 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](#lazy-instantiation-of-rxdatabase--rxcollections)
## API
### `Provider`
The `` 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 ``
```javascript
function useRxDB(): RxDatabase
```
#### Example
```javascript
const db = useRxDB();
```
### `useRxCollection`
Given a collection name returns an RxCollection instance, if found in RxDatabase.
```javascript
function useRxCollection(name: string): RxCollection | null
```
#### Example
```javascript
const collection = useRxCollection('characters');
```
### `useRxQuery`
Subscribes to given RxQuery object providing query results and some helpful extra state variables.
```javascript
function useRxQuery(query: RxQuery, options?: UseRxQueryOptions): RxQueryResult
```
#### `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`
| Property | Type | Description |
| ------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `result` | `T[] \| RxDocument[]` | 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
```javascript
const collection = useRxCollection('characters');
const query = collection.find().where('affiliation').equals('Jedi');
const { result } = useRxQuery(query);
```
#### Infinite Scroll Pagination Example
```javascript
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 (
{characters.map((character, index) => (
))}
{!isExhausted && load more}
);
```
#### Traditional Pagination Example
```javascript
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 (
{characters.map((character, index) => (
))}
{Array(pageCount)
.fill()
.map((x, i) => (
{
fetchPage(i + 1);
}}
>
page {i + 1}
))}
);
```
### `useRxData`
Convenience wrapper around `useRxQuery` that expects a collection name & a query constructor function
```javascript
function useRxData(
collectionName: string,
queryConstructor: ((collection: RxCollection) => RxQuery | undefined) | undefined,
options?: UseRxQueryOptions
): RxQueryResult
```
#### Example
```javascript
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`):
```javascript
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:
```javascript
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:
```javascript
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](https://rxdb.info/rx-document.html#functions)
and [RxCollection](https://rxdb.info/rx-collection.html#functions):
#### Example
```javascript
const collection = useRxCollection('characters');
collection.upsert({
name: 'Luke Skywalker',
affiliation: 'Jedi',
});
```
## LICENSE
MIT