IndexedDB Implementation: Claude Code 활용 가이드
indexeddb implementation: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.
IndexedDBを選ぶ理由
localStorageは手軽ですが、容量制限(5MB程度)や데이터構造の制約があります。IndexedDBは数百MB이상의데이터を構造化して저장でき、인덱스에 의한高速검색も가능합니다。Claude Code를 활용하면 IndexedDBの複雑なAPIをラップした使いやすい데이터アクセス層を구축할 수 있습니다。
타입安全なIndexedDBラッパー
> IndexedDBを타입安全に操作できるラッパー클래스を作って。
> CRUD操作と인덱스검색に대응して。
interface StoreConfig {
name: string;
keyPath: string;
indexes?: { name: string; keyPath: string; unique?: boolean }[];
}
class Database {
private db: IDBDatabase | null = null;
constructor(
private name: string,
private version: number,
private stores: StoreConfig[]
) {}
async open(): Promise<void> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.name, this.version);
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
for (const store of this.stores) {
if (!db.objectStoreNames.contains(store.name)) {
const objectStore = db.createObjectStore(store.name, { keyPath: store.keyPath });
store.indexes?.forEach((idx) => {
objectStore.createIndex(idx.name, idx.keyPath, { unique: idx.unique });
});
}
}
};
request.onsuccess = () => { this.db = request.result; resolve(); };
request.onerror = () => reject(request.error);
});
}
private getStore(name: string, mode: IDBTransactionMode) {
if (!this.db) throw new Error('データベースが開かれていません');
return this.db.transaction(name, mode).objectStore(name);
}
async put<T>(storeName: string, data: T): Promise<void> {
return new Promise((resolve, reject) => {
const request = this.getStore(storeName, 'readwrite').put(data);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
async get<T>(storeName: string, key: IDBValidKey): Promise<T | undefined> {
return new Promise((resolve, reject) => {
const request = this.getStore(storeName, 'readonly').get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async getAll<T>(storeName: string): Promise<T[]> {
return new Promise((resolve, reject) => {
const request = this.getStore(storeName, 'readonly').getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async delete(storeName: string, key: IDBValidKey): Promise<void> {
return new Promise((resolve, reject) => {
const request = this.getStore(storeName, 'readwrite').delete(key);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
async findByIndex<T>(storeName: string, indexName: string, value: IDBValidKey): Promise<T[]> {
return new Promise((resolve, reject) => {
const index = this.getStore(storeName, 'readonly').index(indexName);
const request = index.getAll(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
}
実際の애플리케이션での使用例
// 데이터베이스定義
const db = new Database('myApp', 1, [
{
name: 'notes',
keyPath: 'id',
indexes: [
{ name: 'by-category', keyPath: 'category' },
{ name: 'by-updated', keyPath: 'updatedAt' },
],
},
]);
// 초기화
await db.open();
// ノートの저장
await db.put('notes', {
id: crypto.randomUUID(),
title: '会議メモ',
content: '本日の議題...',
category: 'work',
updatedAt: Date.now(),
});
// 카테고리で검색
const workNotes = await db.findByIndex('notes', 'by-category', 'work');
서버との동기
class SyncManager {
private db: Database;
constructor(db: Database) {
this.db = db;
}
async syncToServer(storeName: string, apiEndpoint: string) {
const pending = await this.db.findByIndex<any>(storeName, 'by-sync', 'pending');
for (const item of pending) {
try {
await fetch(apiEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(item),
});
await this.db.put(storeName, { ...item, syncStatus: 'synced' });
} catch {
console.log('同期失敗。オンライン復帰時に再試行します。');
break;
}
}
}
}
// オンライン復帰時に自動동기
window.addEventListener('online', () => {
syncManager.syncToServer('notes', '/api/notes/sync');
});
Reactフックとの통합
function useIndexedDB<T>(storeName: string, key?: IDBValidKey) {
const [data, setData] = useState<T | T[] | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
const load = key
? db.get<T>(storeName, key)
: db.getAll<T>(storeName);
load.then(setData).finally(() => setLoading(false));
}, [storeName, key]);
return { data, loading };
}
정리
Claude Code를 활용하면 IndexedDBの複雑なAPIを타입安全にラップし、オフライン대응や서버동기まで효율적으로구현할 수 있습니다。Service Workerとの연동はService Worker활용を、캐시戦略は캐시戦略를 참고하세요.
IndexedDB API의 사양은MDN Web Docs - IndexedDB를 확인하세요.
#Claude Code
#IndexedDB
#ローカルストレージ
#offline
#TypeScript
Related Posts
Tips & Tricks
Tips & Tricks
Claude Code 생산성을 3배로 높이는 10가지 팁
Claude Code를 더 효과적으로 활용하는 10가지 실전 팁을 공개합니다. 프롬프트 전략부터 워크플로 단축키까지, 오늘부터 바로 적용해 보세요.
Tips & Tricks
Tips & Tricks
Canvas/WebGL Optimization: Claude Code 활용 가이드
canvas/webgl optimization: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.
Tips & Tricks
Tips & Tricks
Markdown Implementation: Claude Code 활용 가이드
markdown implementation: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.