React 用 IndexedDB 做离线优先:借助 idb 把数据缓存在浏览器,断网也能用
test12026-11-020 次阅读
为什么 localStorage 不够用
前端想做离线优先,第一反应往往是 localStorage。它确实简单,但有两个硬伤:容量只有约 5MB,且只能存字符串。一旦要缓存列表、草稿、离线提交队列这类结构化且体量不小的数据,localStorage 很快就会不够。IndexedDB 是浏览器内置的事务型数据库,容量按磁盘剩余空间算,能存对象、二进制(Blob/ArrayBuffer),还支持索引查询。直接用原生 IndexedDB API 很啰嗦,社区里 idb 这个库把它包成了 Promise,写起来接近 async/await 的常规数据库操作。
用 idb 封装一个 Repository
把“打开数据库 + 建表 + 读写”收敛到一个模块,组件层只关心业务语义,不关心底层 API。
import { openDB } from 'idb';
const DB_NAME = 'app-cache';
const STORE = 'articles';
async function getDB() {
return openDB(DB_NAME, 1, {
upgrade(db) {
if (!db.objectStoreNames.contains(STORE)) {
const store = db.createObjectStore(STORE, { keyPath: 'id' });
store.createIndex('by-updated', 'updatedAt');
}
},
});
}
export async function cacheArticles(list) {
const db = await getDB();
const tx = db.transaction(STORE, 'readwrite');
for (const item of list) {
await tx.store.put({ ...item, updatedAt: Date.now() });
}
await tx.done;
}
export async function getCachedArticles() {
const db = await getDB();
return db.getAll(STORE);
}
export async function getCached(id) {
const db = await getDB();
return db.get(STORE, id);
}
在 React 里用自定义 Hook 读写
把读取逻辑包成 Hook,组件挂载时先读缓存,保证断网也有内容可渲染。
import { useEffect, useState } from 'react';
import { getCachedArticles, cacheArticles } from './db';
export function useArticles() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let active = true;
(async () => {
// 1. 先读本地缓存,秒出
const local = await getCachedArticles();
if (active && local.length) setItems(local);
// 2. 再请求网络,回填缓存
try {
const res = await fetch('/api/articles');
const data = await res.json();
if (active) setItems(data);
await cacheArticles(data); // 写入 IndexedDB
} catch (e) {
// 断网:local 中已有内容,静默降级
} finally {
if (active) setLoading(false);
}
})();
return () => { active = false; };
}, []);
return { items, loading };
}
离线优先的两条铁律
- 读路径永远先落本地:打开页面第一帧就展示缓存,网络只是“刷新”而非“唯一来源”。
- 写路径走“乐观写 + 离线队列”:本地先写成功,失败的请求塞进一个待发送队列,恢复网络后再重放,用 updatedAt 或版本号做冲突裁决。
这样即便地铁里信号全无,用户依然能看列表、能写草稿,恢复连接后数据自动同步。IndexedDB 不是银弹,它不擅长频繁小写的场景(那种仍该用内存 + 防抖落盘),但对“离线只读 + 批量回写”的资讯类应用,是最稳的底盘。
T
test1
文章作者
为什么 localStorage 不够用 前端想做离线优先,第一反应往往是 localStorage。它确实简单,但有...
- 分类
- 技术
- 发布时间
- 2026-11-02
- 字数
- 约 2280 字
- 阅读
- 0 次
