Skip to content

useIndexedDB

Saurav-TB-Pandey edited this page Aug 5, 2026 · 1 revision

useIndexedDB

A powerful, high-performance React hook for safely persisting state asynchronously in the browser using IndexedDB. This hook provides the familiar ergonomics of useState, but stores values that outlive browser reloads and easily handles vast amounts of structured data like arrays, blobs, and dates without the blocking performance constraints of localStorage.

Features built-in:

  • Global connection pooling: Safely handles opening the database connection exactly once and handles store creation.
  • Familiar API: Uses the tuple [value, setValue] identical to useState with a third meta parameter for IndexedDB state.
  • Auto-Sync: Instantly synchronizes your hook state across all open browser tabs using the native BroadcastChannel.
  • Updater Pattern: Supports robust updates via setValue(prev => [...prev, newItem]).
  • Zero serialization: Native IndexedDB structured cloning preserves raw JS objects (no JSON.stringify needed!).

Global Configuration (Required)

Before calling useIndexedDB anywhere in your component tree, you must initialize the global database connection. The best place to do this is in your app's entry file (e.g. index.tsx, App.tsx, or _app.tsx).

import { createIndexedDB } from 'react-hook-lab';

// Initialize the database once
createIndexedDB({
  dbName: 'my-app-database',
  version: 1, // Bump this if you add new stores in the future
  stores: ['settings', 'cache', 'users']
});

Basic Usage

import { useIndexedDB } from 'react-hook-lab';

function SettingsPanel() {
  const [theme, setTheme, { status }] = useIndexedDB('settings', 'theme-pref', 'light');

  // IndexedDB is asynchronous!
  if (status === 'loading') {
    return <p>Loading preferences...</p>;
  }

  return (
    <div>
      <p>Current theme: {theme}</p>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
      <button onClick={() => setTheme('light')}>Light Mode</button>
    </div>
  );
}

Advanced API

setValue(updater)

Just like React's useState, you can pass a function to update the value based on its previous state.

const [history, setHistory] = useIndexedDB('cache', 'search-history', []);

// Add item without needing a stale reference to `history`
const addSearch = (term) => {
  setHistory((prev) => [...prev, term]);
};

Deleting Records

Use the meta.remove() method to erase the key entirely from the database and revert the local state back to the fallback initialValue.

const [user, setUser, { remove, status }] = useIndexedDB('users', 'active-profile', null);

const handleLogout = async () => {
  await remove();
  // user is now instantly `null`, and the DB record is deleted
};

Error Handling

If IndexedDB is blocked by privacy settings or disk quota limits, meta.status will transition to "error".

const [data, setData, { status, error }] = useIndexedDB('cache', 'api-results', []);

if (status === 'error') {
  console.error("IndexedDB Error:", error.message);
}

Cross-Tab Sync (Magic! 🪄)

Because useIndexedDB leverages BroadcastChannel under the hood, it automatically syncs state across multiple browser tabs!

If a user changes their theme to "dark" in Tab A:

  1. setValue('dark') writes to IndexedDB.
  2. A broadcast message is fired.
  3. Tab B instantly detects the broadcast and updates its local theme state to "dark".

You do not need to configure anything to enable this behavior; it works securely out of the box!

Clone this wiki locally