mcpField
T
tanstack-db

tanstack-db

github.com/tanstack-skills数据与数据库361.6k 次安装39 周前更新
代码仓库

关于 tanstack-db

tanstack-db 是介绍 TanStack DB 的 Skill;TanStack DB 是基于差分数据流的客户端嵌入式数据库层,目前处于 Beta 阶段。内容涵盖规范化集合、响应式实时查询、乐观变更,以及与 TanStack Query 和多种数据源的集成。

主要功能

  1. 01适配多种数据源的规范化集合
  2. 02类 SQL 构造器的响应式实时查询
  3. 03自动乐观更新与失败回滚
  4. 04增量式查询计算
  5. 05主动和按需同步模式

适用场景

  1. 01在客户端应用中构建响应式数据视图
  2. 02变更同步时立即更新界面
  3. 03查询和连接规范化集合
  4. 04按需加载大型集合

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tanstack-skills/tanstack-skills --skill tanstack-db

安装后在 Claude Code 中输入/tanstack-db确认已加载。

详细介绍

概述

TanStack DB 是一个基于差分数据流构建的客户端嵌入式数据库层。它维护规范化集合,使用增量计算执行实时查询,提供自动乐观更新,并与 TanStack Query 集成以获取数据。即使处理 10 万多行数据,更新也能在亚毫秒级完成。

软件包: @tanstack/react-db 查询集成: @tanstack/query-db-collection 状态: Beta(v0.5)

安装

npm install @tanstack/react-db @tanstack/query-db-collection

核心概念

  • 集合:封装数据源(TanStack Query、Electric 等)的规范化数据存储
  • 实时查询:使用类 SQL 查询构建器的响应式订阅
  • 乐观更新:失败时自动即时更新 UI 并回滚
  • 差分数据流:发生更改时仅重新计算受影响的查询结果

集合

创建集合
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>
}
查询构建器 API
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
无需手动编写样板代码
之前(仅使用 TanStack Query)之后(TanStack DB)
手动使用 onMutate 管理乐观状态自动
手动编写 onError 回滚逻辑自动
每次更新都要失效缓存所有实时查询都会自动更新

查询驱动同步(按需)

实时查询会自动生成经过优化的网络请求:

// 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())
}

性能

操作延迟
更新单行(10 万行已排序的集合)~0.7 ms
后续查询(同步后)<1 ms
跨集合联接亚毫秒级

支持的集合类型

  • Query 集合 - TanStack Query 集成
  • Electric 集合 - Electric SQL 实时同步
  • TrailBase 集合 - TrailBase 后端
  • RxDB 集合 - RxDB 集成
  • PowerSync 集合 - PowerSync 同步
  • LocalStorage 集合 - 浏览器持久化
  • LocalOnly 集合 - 仅内存存储

API 摘要

import { createCollection, useLiveQuery } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'
import { eq, lt, and, parseLoadSubsetOptions } from '@tanstack/db'

最佳实践

  1. 在模块级别定义集合 - 集合是单例
  2. 选择合适的同步模式:eager(<1 万条)、on-demand(>5 万条)、progressive(协作场景)
  3. 使用联接而非视图专用 API - 一次性加载规范化集合
  4. 让 TanStack Query 负责数据获取 - DB 扩展 Query,而不是取代它
  5. 使用 parseLoadSubsetOptions 将实时查询谓词映射为 API 参数
  6. 依赖自动乐观更新 - 不要手动管理乐观状态
  7. 使用模式进行运行时验证和 TypeScript 类型推断
  8. 利用增量计算 - 让引擎处理筛选,而不是手动调用 .filter()

常见问题

  • 在组件内创建集合(应在模块级别创建)
  • 试图完全取代 TanStack Query(DB 构建于其之上)
  • 在渲染期间手动调用 .filter(),而不是使用实时查询的 where 子句
  • 未提供 getKey 以正确规范化数据
  • 忘记用于服务器同步的更新处理器(onInsert、onUpdate、onDelete)

评论

支持 Markdown