重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
tanstack-db by tanstack-skills/tanstack-skills
npx skills add https://github.com/tanstack-skills/tanstack-skills --skill tanstack-dbTanStack DB 是一个基于差分数据流的客户端嵌入式数据库层。它维护规范化的集合,使用增量计算实现实时查询,提供自动乐观更新,并与 TanStack Query 集成以进行数据获取。即使处理超过 10 万行数据,也能实现亚毫秒级的更新。
包: @tanstack/react-db 查询集成: @tanstack/query-db-collection 状态: Beta (v0.5)
npm install @tanstack/react-db @tanstack/query-db-collection
import { createCollection } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'
const todoCollection = createCollection(
queryCollectionOptions({
queryKey: ['todos'],
queryFn: async () => api.todos.getAll(),
getKey: (item) => item.id,
schema: todoSchema,
onInsert: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.create(mutation.modified)
)
)
},
onUpdate: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.update(mutation.modified)
)
)
},
onDelete: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.delete(mutation.original.id)
)
)
},
})
)
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 预加载(默认):预先加载整个集合。适用于 < 10k 行数据。
const smallCollection = createCollection(
queryCollectionOptions({ syncMode: 'eager', /* ... */ })
)
// 按需加载:仅加载查询请求的数据。适用于 > 50k 行数据、搜索场景。
const largeCollection = createCollection(
queryCollectionOptions({
syncMode: 'on-demand',
queryFn: async (ctx) => {
const params = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions)
return api.getProducts(params)
},
})
)
// 渐进式:立即加载查询子集,后台进行完整同步。
const collaborativeCollection = createCollection(
queryCollectionOptions({ syncMode: 'progressive', /* ... */ })
)
import { useLiveQuery } from '@tanstack/react-db'
import { eq } from '@tanstack/db'
function TodoList() {
const { data: todos } = useLiveQuery((query) =>
query
.from({ todos: todoCollection })
.where(({ todos }) => eq(todos.completed, false))
)
return <ul>{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}</ul>
}
const { data } = useLiveQuery((q) =>
q
.from({ t: todoCollection })
.where(({ t }) => eq(t.status, 'active'))
.orderBy(({ t }) => t.createdAt, 'desc')
.limit(10)
)
const { data } = useLiveQuery((q) =>
q
.from({ t: todoCollection })
.innerJoin(
{ u: userCollection },
({ t, u }) => eq(t.userId, u.id)
)
.innerJoin(
{ p: projectCollection },
({ u, p }) => eq(u.projectId, p.id)
)
.where(({ p }) => eq(p.id, currentProject.id))
)
import { eq, lt, and } from '@tanstack/db'
// 等于
eq(field, value)
// 小于
lt(field, value)
// 与
and(eq(product.category, 'electronics'), lt(product.price, 100))
const { data } = useLiveQuery((q) =>
q
.from({ product: productsCollection })
.where(({ product }) =>
and(eq(product.category, 'electronics'), lt(product.price, 100))
)
.orderBy(({ product }) => product.price, 'asc')
.limit(10)
)
todoCollection.insert({
id: uuid(),
text: 'New todo',
completed: false,
})
// 立即:更新所有引用此集合的实时查询
// 后台:调用 onInsert 处理器以与服务器同步
// 失败时:自动回滚
| 之前(仅使用 TanStack Query) | 之后(使用 TanStack DB) |
|---|---|
手动 onMutate 以实现乐观状态 | 自动 |
手动 onError 回滚逻辑 | 自动 |
| 每个更新的缓存失效 | 所有实时查询自动更新 |
实时查询自动生成优化的网络请求:
// 这个实时查询...
useLiveQuery((q) =>
q.from({ product: productsCollection })
.where(({ product }) => and(eq(product.category, 'electronics'), lt(product.price, 100)))
.orderBy(({ product }) => product.price, 'asc')
.limit(10)
)
// ...自动生成:
// GET /api/products?category=electronics&price_lt=100&sort=price:asc&limit=10
queryFn: async (ctx) => {
const { filters, sorts, limit } = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions)
const params = new URLSearchParams()
filters.forEach(({ field, operator, value }) => {
if (operator === 'eq') params.set(field.join('.'), String(value))
else if (operator === 'lt') params.set(`${field.join('.')}_lt`, String(value))
})
if (limit) params.set('limit', String(limit))
return fetch(`/api/products?${params}`).then(r => r.json())
}
| 操作 | 延迟 |
|---|---|
| 单行更新(10 万行已排序集合) | ~0.7 毫秒 |
| 后续查询(同步后) | <1 毫秒 |
| 跨集合连接 | 亚毫秒级 |
import { createCollection, useLiveQuery } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'
import { eq, lt, and, parseLoadSubsetOptions } from '@tanstack/db'
eager (<10k), on-demand (>50k), progressive (协作)parseLoadSubsetOptions 将实时查询谓词映射到 API 参数.filter().filter() 而非实时查询的 where 子句getKey 以实现正确的规范化onInsert, onUpdate, onDelete)每周安装量
67
代码仓库
GitHub 星标数
5
首次出现
2026 年 2 月 21 日
安全审计
安装于
codex63
opencode62
gemini-cli61
cursor61
amp60
github-copilot60
TanStack DB is a client-side embedded database layer built on differential dataflow. It maintains normalized collections, uses incremental computation for live queries, provides automatic optimistic mutations, and integrates with TanStack Query for data fetching. Sub-millisecond updates even with 100k+ rows.
Package: @tanstack/react-db Query Integration: @tanstack/query-db-collection Status: Beta (v0.5)
npm install @tanstack/react-db @tanstack/query-db-collection
import { createCollection } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'
const todoCollection = createCollection(
queryCollectionOptions({
queryKey: ['todos'],
queryFn: async () => api.todos.getAll(),
getKey: (item) => item.id,
schema: todoSchema,
onInsert: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.create(mutation.modified)
)
)
},
onUpdate: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.update(mutation.modified)
)
)
},
onDelete: async ({ transaction }) => {
await Promise.all(
transaction.mutations.map((mutation) =>
api.todos.delete(mutation.original.id)
)
)
},
})
)
// Eager (default): Load entire collection upfront. Best for <10k rows.
const smallCollection = createCollection(
queryCollectionOptions({ syncMode: 'eager', /* ... */ })
)
// On-Demand: Load only what queries request. Best for >50k rows, search.
const largeCollection = createCollection(
queryCollectionOptions({
syncMode: 'on-demand',
queryFn: async (ctx) => {
const params = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions)
return api.getProducts(params)
},
})
)
// Progressive: Load query subset immediately, full sync in background.
const collaborativeCollection = createCollection(
queryCollectionOptions({ syncMode: 'progressive', /* ... */ })
)
import { useLiveQuery } from '@tanstack/react-db'
import { eq } from '@tanstack/db'
function TodoList() {
const { data: todos } = useLiveQuery((query) =>
query
.from({ todos: todoCollection })
.where(({ todos }) => eq(todos.completed, false))
)
return <ul>{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}</ul>
}
const { data } = useLiveQuery((q) =>
q
.from({ t: todoCollection })
.where(({ t }) => eq(t.status, 'active'))
.orderBy(({ t }) => t.createdAt, 'desc')
.limit(10)
)
const { data } = useLiveQuery((q) =>
q
.from({ t: todoCollection })
.innerJoin(
{ u: userCollection },
({ t, u }) => eq(t.userId, u.id)
)
.innerJoin(
{ p: projectCollection },
({ u, p }) => eq(u.projectId, p.id)
)
.where(({ p }) => eq(p.id, currentProject.id))
)
import { eq, lt, and } from '@tanstack/db'
// Equality
eq(field, value)
// Less than
lt(field, value)
// AND
and(eq(product.category, 'electronics'), lt(product.price, 100))
const { data } = useLiveQuery((q) =>
q
.from({ product: productsCollection })
.where(({ product }) =>
and(eq(product.category, 'electronics'), lt(product.price, 100))
)
.orderBy(({ product }) => product.price, 'asc')
.limit(10)
)
todoCollection.insert({
id: uuid(),
text: 'New todo',
completed: false,
})
// Immediately: updates all live queries referencing this collection
// Background: calls onInsert handler to sync with server
// On failure: automatic rollback
| Before (TanStack Query only) | After (TanStack DB) |
|---|---|
Manual onMutate for optimistic state | Automatic |
Manual onError rollback logic | Automatic |
| Per-mutation cache invalidation | All live queries update automatically |
Live queries automatically generate optimized network requests:
// This live query...
useLiveQuery((q) =>
q.from({ product: productsCollection })
.where(({ product }) => and(eq(product.category, 'electronics'), lt(product.price, 100)))
.orderBy(({ product }) => product.price, 'asc')
.limit(10)
)
// ...automatically generates:
// GET /api/products?category=electronics&price_lt=100&sort=price:asc&limit=10
queryFn: async (ctx) => {
const { filters, sorts, limit } = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions)
const params = new URLSearchParams()
filters.forEach(({ field, operator, value }) => {
if (operator === 'eq') params.set(field.join('.'), String(value))
else if (operator === 'lt') params.set(`${field.join('.')}_lt`, String(value))
})
if (limit) params.set('limit', String(limit))
return fetch(`/api/products?${params}`).then(r => r.json())
}
| Operation | Latency |
|---|---|
| Single row update (100k sorted collection) | ~0.7 ms |
| Subsequent queries (after sync) | <1 ms |
| Join across collections | Sub-millisecond |
import { createCollection, useLiveQuery } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'
import { eq, lt, and, parseLoadSubsetOptions } from '@tanstack/db'
eager (<10k), on-demand (>50k), progressive (collaborative)parseLoadSubsetOptions to map live query predicates to API params.filter().filter() in render instead of live query where clausesgetKey for proper normalizationonInsert, onUpdate, onDelete) for server syncWeekly Installs
67
Repository
GitHub Stars
5
First Seen
Feb 21, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
codex63
opencode62
gemini-cli61
cursor61
amp60
github-copilot60
React视图过渡API使用指南:实现原生浏览器动画与状态管理
6,600 周安装