aiyoudiao / react-idb-toolkit

⚛️ Elegant and easy-to-use React toolkit for managing local data with IndexedDB, powered by [idb](https://github.com/jakearchibald/idb).

Home Page:https://aiyoudiao.github.io/react-idb-toolkit/demo-dist/index.html

Repository from Github https://github.comaiyoudiao/react-idb-toolkitRepository from Github https://github.comaiyoudiao/react-idb-toolkit

🚀 react-idb-toolkit

简体中文 | English

DeepWiki Knowledge Base Document -> react-idb-toolkit
⚛️ Elegant and easy-to-use React toolkit for managing local data with IndexedDB, powered by idb.
A lightweight, simple React hook for storing structured data in the browser via IndexedDB. Supports multiple store initialization, common CRUD operations (get/set/delete/clear), with full TypeScript support and test cases.

npm license issues

Visit Example | Visit Storybook Example

Logo


📦 Installation

npm install react-idb-toolkit
# or
yarn add react-idb-toolkit

✨ Features

  • ✅ Simple API powered by idb
  • 🔁 Automatically creates multiple object stores
  • 🧪 Built-in unit tests with Vitest
  • 📖 Interactive Storybook Playground
  • 🧠 Fully based on React Hooks with type inference and generics
  • 📦 Zero external dependencies (except for idb)

🛠️ Supper Simple Hook Usage

View Demo | View Code

import { useIndexedDBState } from 'react-idb-toolkit';

export const CounterExample = () => {
  const [count, setCount, { loading }] = useIndexedDBState<number>({
    storeName: "demoStore",
    key: "counter",
    defaultValue: 0,
  });

  return (
    <div className="p-6 text-center space-y-4">
      <h2 className="text-xl font-semibold">Persistent Counter</h2>
      <p className="text-4xl font-bold">{loading ? "..." : count}</p>
      <div className="flex gap-2 justify-center">
        <button onClick={() => setCount((c) => c + 1)}>Increment</button>
        <button variant="outline" onClick={() => setCount(0)}>
          Reset
        </button>
      </div>
    </div>
  )
};

⚙️ Supper Simple Hook Options

interface UseIndexedDBStateOptions<T> {
  storeName: string;
  key: IDBValidKey;
  defaultValue?: T | (() => T);
  onError?: (error: Error) => void;
}

📦 Supper Simple Hook Return Values

[
  value: T;
  setValue: React.Dispatch<React.SetStateAction<T>>;
  {
    loading: boolean;
    sync: () => Promise<...>;
  }
]

🛠️ Supper Simple Context Usage

View Demo | View Code

import {
  IndexedDBStateProvider,
  useIndexedDBStateContext,
} from 'react-idb-toolkit';


const DemoComponent = () => {
  const [value, setValue] = useIndexedDBStateContext<string>("demoKey", "default");

  return (
    <div className="p-4 space-y-4">
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <p>Current value: {value}</p>
    </div>
  );
};

export const SingleContextUsage = () => (
  <IndexedDBStateProvider storeName="context-store">
    <div className="flex items-center justify-center h-screen bg-gray-100">
      <div className="p-6 space-y-6 max-w-md w-full">
        <h2 className="text-xl font-semibold">Context Demo</h2>
        <DemoComponent />
      </div>
    </div>
  </IndexedDBStateProvider>
);

⚙️ Supper Simple Provider Options

interface IndexedDBStateProviderProps {
  storeName: string;
  children: React.ReactNode;
}

// context params
{
  key: IDBValidKey,
  defaultValue?: T
}

📦 Supper Simple Context Return Values

interface UseIndexedDBStateContextReturn<T> {
  value: T;
  updateValue: React.Dispatch<React.SetStateAction<T>>;
  loading: boolean;
}

🛠️ Hook Usage

View Demo | View Code

import { useIndexedDB } from 'react-idb-toolkit';

const { loading, setItem, getItem, deleteItem, clear, getAll, keys } = useIndexedDB({
  dbName: 'myDatabase',
  storeNames: ['myStore'],
});

useEffect(() => {
  if (!loading) {
    setItem('myStore', 'userName', 'demo');
  }
}, [loading]);

⚙️ Hook Options

interface UseIndexedDBOptions {
  dbName: string;       // Database name
  version?: number;     // Database version, default is 1
  storeNames: string[]; // List of object store names
}

📦 Hook Return Values

interface UseIndexedDBReturn {
  loading: boolean;
  getItem: <T>(storeName: string, key: IDBValidKey) => Promise<T | undefined>;
  setItem: <T>(storeName: string, key: IDBValidKey, value: T) => Promise<void>;
  deleteItem: (storeName: string, key: IDBValidKey) => Promise<void>;
  clear: (storeName: string) => Promise<void>;
  getAll: <T>(storeName: string) => Promise<T[] | undefined>;
  keys: (storeName: string) => Promise<IDBValidKey[] | undefined>;
}

🛠️ Context Usage

View Demo | View Code

import { IndexedDBProvider } from 'react-idb-toolkit';

<IndexedDBProvider
  options={{
    dbName: "storybook-db",
    storeNames: ["demoStore"],
  }}
>
  <PlaygroundContent />
</IndexedDBProvider>
import { useIndexedDBContext } from 'react-idb-toolkit';

const { loading, setItem, getItem, deleteItem, getAll, keys, clear } =
  useIndexedDBContext();

useEffect(() => {
  if (!loading) {
    setItem('demoStore', 'userName', 'demo');
  }
}, [loading]);

⚙️ Provider Options

interface IndexedDBOptions {
  dbName: string;       // Database name
  version?: number;     // Database version, default is 1
  storeNames: string[]; // List of object store names
}

interface IndexedDBProviderProps {
  children: ReactNode;
  options: IndexedDBOptions;
}

📦 Context Return Values

interface UseIndexedDBReturn {
  loading: boolean;
  getItem: <T>(storeName: string, key: IDBValidKey) => Promise<T | undefined>;
  setItem: <T>(storeName: string, key: IDBValidKey, value: T) => Promise<void>;
  deleteItem: (storeName: string, key: IDBValidKey) => Promise<void>;
  clear: (storeName: string) => Promise<void>;
  getAll: <T>(storeName: string) => Promise<T[] | undefined>;
  keys: (storeName: string) => Promise<IDBValidKey[] | undefined>;
}

🛠️ Utils Usage

View Demo | View Code

import { initIndexedDB, getIndexedDBHelper } from "./toolkit";

let db: IndexedDBHelper | null = null;


useEffect(() => {
  initIndexedDB({
    dbName: "storybook-db",
    storeNames: ["demoStore"],
  }).then(() => {
    db = getIndexedDBHelper();
    const { setItem, getItem, deleteItem, clear, getAll, keys } = db;
    setItem("demoStore", "userName", "demo");
  });
}, []);

⚙️ initIndexedDB Options

interface IndexedDBOptions {
  dbName: string;       // Database name
  version?: number;     // Database version, default is 1
  storeNames: string[]; // List of object store names
}

📦 getIndexedDBHelper Return Values

interface UseIndexedDBReturn {
  loading: boolean; //  Indicates if DB is still initializing
  getItem<T>(store, key): Promise<T | undefined>;
  setItem<T>(store, key, value): Promise<void>;
  deleteItem(store, key): Promise<void>;
  clear(store): Promise<void>;
  getAll<T>(store): Promise<T[]>;
  keys(store): Promise<IDBValidKey[]>;
}

🧪 Testing

Tests are written using Vitest, with fake-indexeddb to simulate browser environment:

npm test

Covered test cases include:

  • Data insertion, retrieval, deletion, and clearing
  • Fetching all keys and values
  • Error handling when DB is not initialized

📖 Storybook Playground

Start an interactive Storybook playground with:

npm run storybook

Logo

You can:

  • Add key/value data manually
  • View all keys and values
  • Delete or clear data
  • Observe dynamic hints and state updates

Perfect for debugging and demos.


🔧 Local Development

git clone https://github.com/aiyoudiao/react-idb-toolkit.git
cd react-idb-toolkit
npm install

# Run tests
npm run test:ui

# Start Demo
npm run dev:demo

Logo Logo


📄 License

MIT License © aiyoudiao


💬 Acknowledgements

  • idb: A modern IndexedDB wrapper
  • fake-indexeddb: Mock IndexedDB implementation for Node.js
  • Vitest: A fast and modern unit testing framework
  • Storybook: Tool for building UI component demos interactively

Made with ❤️ using idb and React

About

⚛️ Elegant and easy-to-use React toolkit for managing local data with IndexedDB, powered by [idb](https://github.com/jakearchibald/idb).

https://aiyoudiao.github.io/react-idb-toolkit/demo-dist/index.html

License:MIT License


Languages

Language:TypeScript 83.8%Language:JavaScript 10.6%Language:CSS 4.2%Language:Handlebars 1.4%