react-indexed-db
Version:
React wrapper to IndexedDB database.
493 lines (392 loc) • 11.4 kB
Markdown
# react-indexed-db-hook
react-indexed-db-hook is forked from [react-indexed-db](https://github.com/assuncaocharles/react-indexed-db). This library is a wrapper around the browser's IndexedDB database in an "easier to use" React Hook.
## Installation
```js
npm install react-indexed-db-hook
```
## Creating the DB
You can choose to work with the indexed db as an context or to use it as a hook. However, I don't plan on supporting the context, but it's there if you want it.
### To use it as a hook
- First initialized your DB before to be able to use the hooks inside other components:
```js
//DBConfig.js|tsx
export const DBConfig = {
name: "MyDB",
version: 1,
objectStoresMeta: [
{
store: "people",
storeConfig: { keyPath: "id", autoIncrement: true },
storeSchema: [
{ name: "name", keypath: "name", options: { unique: false } },
{ name: "email", keypath: "email", options: { unique: false } },
],
},
],
};
```
```js
//App.js|tsx
import React from "react";
import { DBConfig } from "./DBConfig";
import { initDB } from "react-indexed-db-hook";
initDB(DBConfig);
const App: React.FC = () => {
return <div>...</div>;
};
```
### To use it as a context:
- First you have to declare inside `<IndexedDB></IndexedDB>` all the components you want to be able access the DB:
```js
import { IndexedDB } from "react-indexed-db-hook";
import PanelExample from "./Panel";
function App() {
return (
<IndexedDB
name="MyDB"
version={1}
objectStoresMeta={[
{
store: "people",
storeConfig: { keyPath: "id", autoIncrement: true },
storeSchema: [
{ name: "name", keypath: "name", options: { unique: false } },
{ name: "email", keypath: "email", options: { unique: false } },
],
},
]}
>
<Panel />
</IndexedDB>
);
}
```
## Accessing and working with the DB
- In any component inside this context or in an app using the hooks after creating the DB you can consume it like bellow:
```js
// Context
import { AccessDB } from 'react-indexed-db-hook';
export default function PanelExample() {
return (
<AccessDB objectStore="people">
{db => {
console.log('MyDB: ', db);
return <div>{JSON.stringify(db)}</div>;
}}
</AccessDB>
);
}
// Hooks
import { useIndexedDB } from 'react-indexed-db-hook';
export default function PanelExample() {
const db = useIndexedDB('people');
return (<div>{JSON.stringify(db)}</div>);
}
```
#### getByID(id)
It returns the object that is stored in the objectStore by its id.
**getByID** returns a promise that is resolved when we have the object or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ getById }) => {
const [person, setPerson] = useState(null);
getById("people", 1).then(
(personFromDB) => {
setPerson(personFromDB);
},
(error) => {
console.log(error);
},
);
return <div>{person}</div>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function ByID() {
const { getByID } = useIndexedDB("people");
const [person, setPerson] = useState();
useEffect(() => {
getById(1).then((personFromDB) => {
setPerson(personFromDB);
});
}, []);
return <div>{person}</div>;
}
```
#### getAll()
It returns an array of all the items in the given objectStore.
**getAll** returns a promise that is resolved when we have the array of items or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ getAll }) => {
const [persons, setPersons] = useState(null);
getAll().then(
(peopleFromDB) => {
setPersons(peopleFromDB);
},
(error) => {
console.log(error);
},
);
return (
<div>
{personsFromDB.map((person) => (
<span>{person}</span>
))}
</div>
);
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function ShowAll() {
const { getAll } = useIndexedDB("people");
const [persons, setPersons] = useState();
useEffect(() => {
getAll().then((personsFromDB) => {
setPersons(personsFromDB);
});
}, []);
return (
<div>
{personsFromDB.map((person) => (
<span>{person}</span>
))}
</div>
);
}
```
#### getByIndex(indexName, key)
It returns an stored item using an objectStore's index.
The first parameter is the index and the second is the item to query.
**getByIndex** returns a promise that is resolved when the item successfully returned or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ getByIndex }) => {
const [person, setPerson] = useState(null);
getByIndex("name", "Dave").then(
(personFromDB) => {
setPerson(peopleFromDB);
},
(error) => {
console.log(error);
},
);
return <div>{person}</div>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function ByIndex() {
const { getByIndex } = useIndexedDB("people");
const [person, setPerson] = useState();
useEffect(() => {
getByIndex("name", "Dave").then((personFromDB) => {
setPerson(peopleFromDB);
});
}, []);
return <div>{person}</div>;
}
```
#### add(value, key)
It Adds to the given objectStore the key and value pair.
The firt parameter is the value and the second is the key (if not auto-generated).
**add** returns a promise that is resolved when the value was added or rejected if an error occurred.
Usage example (add without a key since it's configured to be auto generated):
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ add }) => {
const handleClick = () => {
add({ name: "name", email: "email" }).then(
(event) => {
console.log("ID Generated: ", event.target.result);
},
(error) => {
console.log(error);
},
);
};
return <button onClick={handleClick}>Add</button>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function AddMore() {
const { add } = useIndexedDB("people");
const [person, setPerson] = useState();
const handleClick = () => {
add({ name: "name", email: "email" }).then(
(event) => {
console.log("ID Generated: ", event.target.result);
},
(error) => {
console.log(error);
},
);
};
return <button onClick={handleClick}>Add</button>;
}
```
#### update(value, key?)
It updates the given value in the objectStore.
The first parameter is the value to update and the second is the key (if there is no key don't provide it).
**update** returns a promise that is resolved when the value was updated or rejected if an error occurred.
Usage example (update without a key):
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ update }) => {
return (
<button
onClick={() => {
update({ id: 3, name: "NewName", email: "NewEmail" }).then(
() => {
// Do something after update
},
(error) => {
console.log(error);
},
);
}}
>
Update
</button>
);
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function Edit() {
const { update } = useIndexedDB("people");
const [person, setPerson] = useState();
const handleClick = () => {
update({ id: 3, name: "NewName", email: "NewNEmail" }).then((event) => {
alert("Edited!");
});
};
return <button onClick={handleClick}>Update</button>;
}
```
#### delete(key)
deletes the object that correspond with the key from the objectStore.
The first parameter is the key to delete.
**delete** returns a promise that is resolved when the value was deleted or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ deleteRecord }) => {
const handleClick = () => {
deleteRecord(3).then((event) => {
alert("Deleted!");
});
};
return <button onClick={handleClick}>Delete</button>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function Delete() {
const { deleteRecord } = useIndexedDB("people");
const handleClick = () => {
deleteRecord(3).then((event) => {
alert("Deleted!");
});
};
return <button onClick={handleClick}>Delete</button>;
}
```
#### openCursor(cursorCallback, keyRange)
It opens an objectStore cursor to enable iterating on the objectStore.
The first parameter is a callback function to run when the cursor succeeds to be opened and the second is optional IDBKeyRange object.
**openCursor** returns a promise that is resolved when the cursor finishes running or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB objectStore="people">
{({ openCursor }) => {
const handleClick = () => {
openCursor((evt) => {
var cursor = evt.target.result;
if (cursor) {
console.log(cursor.value);
cursor.continue();
} else {
console.log("Entries all displayed.");
}
}, IDBKeyRange.bound("A", "F"));
};
return <button onClick={handleClick}>Run cursor</button>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function Open() {
const { openCursor } = useIndexedDB("people");
const handleClick = () => {
openCursor((evt) => {
var cursor = evt.target.result;
if (cursor) {
console.log(cursor.value);
cursor.continue();
} else {
console.log("Entries all displayed.");
}
}, IDBKeyRange.bound("A", "F"));
};
return <button onClick={handleClick}>Run cursor</button>;
}
```
#### clear()
It clears all the data in the objectStore.
**clear** returns a promise that is resolved when the objectStore was cleared or rejected if an error occurred.
Usage example:
```js
// Context
import { AccessDB } from "react-indexed-db-hook";
<AccessDB>
{({ clear }) => {
const handleClick = () => {
clear().then(() => {
alert("All Clear!");
});
};
return <button onClick={handleClick}>Clear All</button>;
}}
</AccessDB>;
// Hooks
import { useIndexedDB } from "react-indexed-db-hook";
function ClearAll() {
const { clear } = useIndexedDB("people");
const handleClick = () => {
clear().then(() => {
alert("All Clear!");
});
};
return <button onClick={handleClick}>Clear All</button>;
}
```
## TODO
- [ ] Improve this documentation
- [x] Implement Hooks `const {getAll, add ...} = useIndexedDB({name, version, dbSchema?})`
- [ ] Handle `getAll()` perfomance issue regarding re-render
- [ ] Implement examples/Demos
- [x] Remove Webpack
- [ ] Add automated tests
## License
Released under the terms of the [MIT License](LICENSE).