Несколько хранилищ в одном приложении

Idb-keyval — это простая обёртка над IndexedDB, которая позволяет хранить ключи и значения без сложной работы с API. В стандартной конфигурации Idb-keyval использует одно хранилище по умолчанию, однако для сложных приложений часто требуется разделять данные по разным категориям, чтобы избежать конфликтов и повысить читаемость данных. Для этого Idb-keyval предоставляет возможность создавать собственные хранилища.

Определение собственного хранилища

Хранилище в Idb-keyval определяется через функцию createStore. Она принимает два параметра:

import { createStore } from 'idb-keyval';

const myStore = createStore('my-database', 'my-store');
  • ‘my-database’ — имя базы данных IndexedDB, в которой будет храниться набор ключей и значений.
  • ‘my-store’ — имя объекта хранилища (object store) внутри базы данных.

Каждое создание хранилища через createStore позволяет полностью изолировать набор данных, что особенно полезно при работе с разными модулями приложения.

Использование методов с пользовательским хранилищем

Все стандартные методы Idb-keyval (get, set, del, clear, keys) поддерживают параметр хранилища. Пример использования:

import { get, set, del, clear, keys } from 'idb-keyval';

// Создание отдельного хранилища
const settingsStore = createStore('app-db', 'settings');
const cacheStore = createStore('app-db', 'cache');

// Добавление данных
await set('theme', 'dark', settingsStore);
await set('userData', { name: 'Alice' }, cacheStore);

// Получение данных
const theme = await get('theme', settingsStore);
const userData = await get('userData', cacheStore);

// Удаление данных
await del('theme', settingsStore);

// Очистка всего хранилища
await clear(cacheStore);

Изоляция данных и предотвращение конфликтов

Использование отдельных хранилищ позволяет:

  • Разделять логические блоки данных: например, настройки приложения и кэшированные результаты запросов.
  • Избегать случайного затирания данных, если разные модули используют одинаковые ключи.
  • Облегчить управление данными при масштабировании приложения.

Например, ключ userData в хранилище settings может содержать одни данные, а в хранилище cache — другие, и они не будут пересекаться.

Масштабирование с несколькими хранилищами

При работе с большим приложением можно создать отдельные хранилища для каждого модуля:

const authStore = createStore('app-db', 'auth');
const uiStore = createStore('app-db', 'ui');
const analyticsStore = createStore('app-db', 'analytics');

Это упрощает логику кода:

  • Модуль аутентификации хранит токены и информацию о пользователе в authStore.
  • UI-модуль хранит состояние интерфейса и настройки в uiStore.
  • Аналитика использует analyticsStore для кэширования событий и статистики.

Рекомендации по структуре

  • Не создавать слишком много хранилищ в одной базе данных, так как это может усложнить миграцию схемы и увеличивает нагрузку на IndexedDB.
  • Группировать данные по логическим категориям, а не по отдельным ключам.
  • Использовать единый префикс для ключей, если требуется хранение множества похожих объектов в одном хранилище, чтобы облегчить поиск и удаление.

Получение всех ключей и данных из конкретного хранилища

Метод keys позволяет получить список всех ключей в указанном хранилище:

const allKeys = await keys(authStore);

С помощью цикла можно легко извлечь все данные:

for (const key of allKeys) {
    const value = await get(key, authStore);
    console.log(key, value);
}

Это удобно для резервного копирования или синхронизации данных.

Практические сценарии

  1. Настройки и кэш: Хранение настроек пользователя отдельно от временных данных кэша.

  2. Мультипользовательские приложения: Для каждого пользователя можно создать отдельное хранилище в одной базе, чтобы изолировать данные.

  3. Модули с разными сроками жизни данных: Например, аналитика может очищаться чаще, чем пользовательские настройки, что упрощается при использовании отдельных хранилищ.

Использование нескольких хранилищ в Idb-keyval обеспечивает гибкость и безопасность данных, позволяя управлять ими на уровне модулей, избегать конфликтов ключей и поддерживать масштабируемость приложения.