A small, reactive IndexedDB binding for React.
npm i indexeddb-hookedYou define your schema in a config object and establish a database connection via open function somewhere in your app.
import React from 'react';
import { open } from 'indexeddb-hooked';
const config = {
name: 'FruitDB',
version: 1,
objectStores: [
{
name: 'fruits',
options: { autoIncrement: true },
data: ['apple', 'banana', 'kiwi'],
},
{
name: 'fruit-lists',
options: { keyPath: 'id', autoIncrement: true },
indexes: [{ name: 'by_name', keyPath: 'name', options: { unique: true } }],
},
],
onOpenSuccess: () => console.log('DB is open and delicious'),
};
open(config);
const App = () => {
return (
<div>...</div>
);
};
export default App;Config parameters
| Value | Type | |
|---|---|---|
name? |
Name of your database | string |
version? |
Current version of your database | unsigned long long |
objectStores |
Definition of your object stores | ObjectStoreParams[] |
onOpenSuccess? |
Callback function called if the IDBFactory.open request was successful | IDBRequest.onsuccess |
onOpenError? |
Callback function fired when the open request returns an error. | IDBRequest.onerror |
onUpgradeNeeded? |
Callback function fired when the database doesn't already exist or if version number is upgraded. Specify this event handler in case you want full control over the creation of your database schema. | (event, objectStores) => void |
Once the IDB is open, you access your data via useRead hook:
import React from 'react';
import { useRead } from 'indexeddb-hooked';
const FruitsBasket = () => {
const [fruits, { isLoading, error }] = useRead('fruits');
/* Since IDB operations are asynchronous, useRead returns `null`
(or previous result) at first, then triggers render once the data is obtained.*/
if (isLoading) return <div>Loading</div>;
/* You can use isLoading boolean flag and error string
to reflect transaction state */
if (error) return <div>{error}</div>;
return (
<ul>
{fruits.map((fruit) => (
<li>{fruit}</li>
))}
</ul>
);
};To read from IDB, you must specify name of the store you want to read from as a first argument of the useRead function.
To specify request, you must provide a second argument in a form of an object. If only store name is provided, useRead returns all data from specified store.
| Value | Type | |
|---|---|---|
key? |
Returns first data entry with given key | IDBValidKey |
keyRange? |
Returns entries within given key range | IDBKeyRange |
direction? |
Specify direction of read result | next, nextunique, prev, prevunique |
index? |
Specify index to search by other value than the primary key | string |
filter? |
Filter function | (value) => boolean |
returnWithKey? |
Data is returned with its key in a form of { value, key } object |
boolean |
Example
import React from 'react';
import { useRead } from 'indexeddb-hooked';
const FruitsBasket = () => {
const [fruits] = useRead('fruits',{
returnWithKey: true,
keyRange: IDBKeyRange.bound(0, 2),
direction:'prev'
});
if (!fruits) return <div>Loading</div>;
return (
<ul>
{fruits.map((result) => (
<li key={result.key}>{result.value}</li>
))}
</ul>
);
};All data manipulation is happening through update function returned from useUpdate hook:
import React from 'react';
import { useUpdate } from 'indexeddb-hooked';
const AddFruit = () => {
const [update, { result, error }] = useUpdate();
const inputEl = useRef(null);
if (error) console.log(error);
if (result) console.log(`Added fruit with key ${result}`);
const onSubmit = (e) => {
e.preventDefault();
update('fruits', { value: inputEl.current.value });
};
return (
<form onSubmit={onSubmit}>
<input ref={inputEl} />
<button type="submit">Add fruit</button>
</form>
);
};Update triggers re-render on components that read from the updated object store only. You can prevent this rendering by setting the third optional argument of the update function to false.
Behaviour of the update function depends on the definition of your object stores.
To specify update operation, you must provide a second argument in a form of an object.
| Value | Type | |
|---|---|---|
value |
Your input data | boolean, number, string, date, object, array, regexp, undefined, Blob,File, null |
key? |
Key of the modified data entry | IDBValidKey |
replace? |
If true, then input data overrides (not merges with) the old data entry | boolean |
Delete your data by specifying key and setting the value update parameter to null.
| Value | Type | |
|---|---|---|
name |
Name of the object store | string |
options? |
Specify supply of your value keys by a key path or a key generator | IDBObjectStoreParameters |
indexes? |
Array containing parameters of indices to create on the database | IndexParams[] |
data? |
Input data entries | boolean[], number[], string[], date[], object[], array[], regexp[], undefined[], Blob[],File[] |
| Value | Type | |
|---|---|---|
keyPath? |
Defines which value of input object is used as a key. If empty or not specified, the object store is created without a key path and uses out-of-line keys. | string,string[] |
autoIncrement? |
If true, the object store has a key generator. Defaults to false. |
boolean |
| Value | Type | |
|---|---|---|
name |
Name of the index | string |
keyPath? |
The key path for the index to use | string,string[] |
options? |
An object with other index attributes | IDBIndexParameters |
| Value | Type | |
|---|---|---|
unique? |
If true, the index will not allow duplicate values for a single key. | boolean |
multiEntry? |
If true, the index will add an entry in the index for each array element when the keyPath resolves to an Array. If false, it will add one single entry containing the Array. |
boolean |
You can also use promise-based alternatives to useRead and useUpdate functions, like so:
import { read, update } from 'indexeddb-hooked';
read('fruits').then(result => console.log(result));
// result is the key or key array of modified object(s)
update('fruits', { value: 'pear' }).then(result => console.log(result);Be sure to use these functions after the database connection has been established.
In case you need to react to changes outside of React, you can subscribe listeners to specified store:
import { subscribe } from 'indexeddb-hooked';
// returns function to unsubscribe the listener
// result is the key or key array of modified object(s)
const unsub = subscribe('fruits', result => console.log(result));