Hone logo
Hone
Problems

React useIndexedDB Hook for Persistent Data Storage

This challenge asks you to create a custom React hook, useIndexedDB, that simplifies interacting with IndexedDB within your React components. IndexedDB provides a client-side, NoSQL database, allowing you to persist data locally in the browser, which is useful for offline functionality, caching, and storing user preferences. This hook will abstract away the complexities of IndexedDB API calls, providing a clean and reusable interface for your components.

Problem Description

You need to implement a useIndexedDB hook in TypeScript that provides a simplified interface for interacting with an IndexedDB database. The hook should accept a database name as an argument and return an object with methods for creating, reading, updating, and deleting data within a specified object store.

Key Requirements:

  • Database Initialization: The hook should initialize the IndexedDB database when it's first called. If the database already exists, it should connect to it.
  • Object Store Management: The hook should allow the user to specify an object store name. It should create the object store if it doesn't exist.
  • CRUD Operations: The hook should provide methods for:
    • create(data: any): Adds new data to the object store.
    • read(key: any): Promise<any | undefined>: Retrieves data from the object store based on a key. Returns undefined if the key doesn't exist.
    • update(key: any, data: any): Updates existing data in the object store based on a key.
    • delete(key: any): Deletes data from the object store based on a key.
  • Error Handling: The hook should handle potential errors during IndexedDB operations and return appropriate error messages.
  • Cleanup: The hook should clean up any open database connections when the component unmounts.

Expected Behavior:

  • The hook should return an object with the create, read, update, and delete methods.
  • All asynchronous operations (CRUD) should return Promises.
  • The hook should handle cases where the database or object store doesn't exist.
  • The hook should gracefully handle errors during database operations.

Edge Cases to Consider:

  • Database already exists.
  • Object store already exists.
  • Object store doesn't exist.
  • Key not found during read, update, or delete.
  • Invalid data types being stored.
  • Browser doesn't support IndexedDB.

Examples

Example 1:

Input: useIndexedDB("myDatabase", "myObjectStore")
Output: {
  create: (data: any) => Promise<void>,
  read: (key: any) => Promise<any | undefined>,
  update: (key: any, data: any) => Promise<void>,
  delete: (key: any) => Promise<void>
}
Explanation: The hook initializes a database named "myDatabase" and an object store named "myObjectStore". It returns an object with CRUD methods.

Example 2:

Input:  Component using useIndexedDB("myDatabase", "myObjectStore") and calling create({id: 1, name: "Test"})
Output:  Data with id 1 and name "Test" is stored in the "myObjectStore" within "myDatabase".
Explanation: The create method successfully adds the provided data to the object store.

Example 3: (Edge Case - Key Not Found)

Input: useIndexedDB("myDatabase", "myObjectStore") and calling read(999) after no data with key 999 exists.
Output: Promise<undefined>
Explanation: The read method returns undefined because no data exists with the specified key.

Constraints

  • The hook must be written in TypeScript.
  • The hook should be compatible with modern browsers that support IndexedDB.
  • The hook should handle errors gracefully and avoid crashing the application.
  • The hook should be reasonably performant for common use cases (e.g., storing and retrieving small to medium-sized data objects). Avoid unnecessary database operations.
  • The database name and object store name should be strings.

Notes

  • Consider using useEffect to initialize the database and clean up resources.
  • You can use indexedDB.open() to open the database and objectStore.put() for creating/updating data, objectStore.get() for reading, and objectStore.delete() for deleting.
  • Think about how to handle potential errors during database operations and provide informative error messages.
  • The hook should be reusable across different components.
  • Focus on creating a clean and well-documented API.
  • Consider using a transaction for multiple operations to ensure atomicity.
Loading editor...
typescript