React+TypeScript环境下向IndexedDB添加值时出现DOMException错误
IndexedDB添加嵌套对象报错的修复方案
问题根源
- KeyPath配置错误:创建对象仓库时,你用动态的
${programId}作为keyPath,这要求存入的对象必须包含一个和当前programId值完全一致的属性名(比如programId是"prog-001",就需要对象有"prog-001"这个属性),但你实际存入的是{ programId: data },对象里只有programId这个固定属性,和keyPath不匹配,导致IndexedDB找不到键值,抛出错误。 - 数据结构不匹配:存入的对象结构和keyPath的预期完全不符,而且这种动态设置keyPath的设计本身就不符合IndexedDB的使用规范——keyPath应该是固定的属性名,用来标识每条数据的唯一主键。
修复方案
推荐方案:使用固定keyPath
把keyPath设为固定的programId,确保存入的对象包含该属性,同时保留嵌套数据结构:
import { openDB } from 'idb'; import { ExternalNestedA, ExternalNestedB } from '../redux-store/app-types/firestoreTypesAndPredicates'; const useIndexDb = () => { const addNestedDocToIndexDb = async (programId: string, data: ExternalNestedA | ExternalNestedB) => { try { // 注意:如果之前创建过版本1的数据库,这里要把版本号改成2才能触发upgrade const db = await openDB('indexTestDB', 2, { upgrade(db) { if (!db.objectStoreNames.contains('data')) { // 固定keyPath为"programId",用它作为主键 db.createObjectStore('data', { keyPath: 'programId' }); } }, }); const transaction = db.transaction('data', 'readwrite'); const store = transaction.objectStore('data'); // 存入包含programId和嵌套data的对象 await store.add({ programId, data }); // 等待事务完成,确保数据写入成功 await transaction.done; console.log('对象已成功添加到IndexedDB'); } catch (error) { console.error('添加对象到IndexedDB失败:', error); } }; return { addNestedDocToIndexDb }; }; export default useIndexDb;
备选方案:使用自增主键或手动指定键
如果不需要用programId作为主键,可以选择以下两种方式:
- 自增主键:创建仓库时开启自增,不用指定keyPath
db.createObjectStore('data', { autoIncrement: true }); - 手动指定键:不设置keyPath,添加数据时传入programId作为键
await store.add(data, programId);
注意事项
- 数据库版本号:如果之前已经初始化过版本1的数据库,必须把版本号调高(比如从1改成2),否则upgrade回调不会执行,无法更新仓库配置。
- 事务完成:务必加上
await transaction.done,保证事务提交成功,避免数据写入异常。
内容的提问来源于stack exchange,提问作者Richardson
相关产品推荐
相关产品推荐

