React Hooks for Dexie.js
dexie-react-hooks provides a collection of React hooks designed for seamlessly integrating Dexie.js, a wrapper for IndexedDB, into React applications. It facilitates reactive data fetching and real-time updates directly from the IndexedDB database, abstracting away the complexities of manual subscription management. The current stable version is 4.4.0, aligning with the broader Dexie.js ecosystem releases. The package follows a release cadence tied closely to the main Dexie.js library, with frequent updates addressing bug fixes and new features, such as enhanced Y.js integration and Dexie Cloud capabilities. Its key differentiators include simplifying reactive state management with IndexedDB, offering idiomatic React patterns for database interactions, and ensuring components re-render automatically when underlying data changes.
Common errors
-
Error: Cannot find module 'dexie-react-hooks' or TypeError: Cannot read properties of undefined (reading 'useLiveQuery')
cause The package is not installed, there's a wrong import path, or a CommonJS/ESM module mismatch.fixEnsure the package is installed with `npm install dexie-react-hooks dexie react react-dom`. Use `import { useLiveQuery } from 'dexie-react-hooks'` in an ESM-compatible environment, or configure your build system for CJS compatibility. -
useLiveQuery does not update when data changes
cause The underlying Dexie operations are not correctly triggering reactivity, the query's dependency array is incorrect, or an outdated Dexie.js version is in use.fixEnsure all database modifications (add, put, delete, update) are done via Dexie's API. Check that your `dexie` package version is `>=4.0.9`. Verify the `useLiveQuery` dependency array includes all external variables used within the query function. -
TypeError: db.table.method is not a function (e.g. db.todos.toArray is not a function)
cause The Dexie database instance or a specific table is not properly initialized, typed, or the database class is not correctly extending `Dexie`.fixReview your Dexie database schema definition, ensuring tables are correctly defined in `db.version().stores({})` and that the `db` instance is correctly created. For TypeScript, ensure proper typing for your database and its tables.
Warnings
- breaking Dexie.js v4.2.0-rc.1 and later introduced a significant change for Y.js users, moving `DexieYProvider` from the `dexie` package into a new `y-dexie` package. While `dexie-react-hooks`'s `useDocument` is related, users integrating Y.js must ensure both `dexie` and `y-dexie` dependencies are correctly installed and imported as per `dexie@4.2.0` and above.
- gotcha This package has a peer dependency on `dexie` version `>=4.2.0-alpha.1 <5.0.0` and `react` version `>=16`. Using incompatible versions of `dexie` or `react` can lead to runtime errors, unexpected behavior, or broken reactivity due to API mismatches or internal inconsistencies.
- gotcha `useLiveQuery` relies on Dexie's internal change tracking for reactivity. For optimal performance and correct re-renders, ensure that all database operations (add, put, delete, update) are performed exclusively through the Dexie instance (e.g., `db.table.method()`). Direct mutations via IndexedDB APIs will not trigger `useLiveQuery` updates.
- gotcha The dependency array for `useLiveQuery` (the second argument) should accurately reflect all external values that, if changed, would require re-executing the query function. An empty array `[]` means the query runs once and then re-subscribes only on database changes; if the query itself depends on component props or state, these must be included in the array to ensure correct reactivity.
Install
-
npm install dexie-react-hooks -
yarn add dexie-react-hooks -
pnpm add dexie-react-hooks
Imports
- useLiveQuery
const useLiveQuery = require('dexie-react-hooks').useLiveQueryimport { useLiveQuery } from 'dexie-react-hooks' - useDexie
import Dexie from 'dexie-react-hooks'; // Incorrectly assuming a default export for the instance
import { useDexie } from 'dexie-react-hooks' - useDocument
import { useDocument } from 'dexie-react-hooks'
Quickstart
import React from 'react';
import { useLiveQuery } from 'dexie-react-hooks';
import Dexie from 'dexie';
// Define your Dexie database schema and class
interface Todo {
id?: number;
title: string;
completed: boolean;
}
class MyDatabase extends Dexie {
todos!: Dexie.Table<Todo, number>;
constructor() {
super('MyTodoDatabase');
this.version(1).stores({
todos: '++id, title, completed'
});
}
}
// Instantiate the database
const db = new MyDatabase();
// React component using the useLiveQuery hook
const TodoList: React.FC = () => {
// useLiveQuery subscribes to changes in db.todos
const todos = useLiveQuery(
() => db.todos.toArray(),
[] // Empty dependency array means the query function is stable; re-queries on DB changes.
);
const addTodo = async () => {
await db.todos.add({ title: `New Todo ${Date.now()}`, completed: false });
};
const toggleTodo = async (id: number) => {
const todo = await db.todos.get(id);
if (todo) {
await db.todos.update(id, { completed: !todo.completed });
}
};
if (!todos) return <div>Loading todos...</div>; // Data is null on first render until query resolves
return (
<div>
<h1>My Todos</h1>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id!)}
/>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.title}
</span>
</li>
))}
</ul>
</div>
);
};
export default TodoList;