一键导入
tanstack-db
Reactive client-first store for your API with collections, live queries, and optimistic mutations.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Reactive client-first store for your API with collections, live queries, and optimistic mutations.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Design engineering principles for making interfaces feel polished. Use when building UI components, reviewing frontend code, implementing animations, hover states, shadows, borders, typography, micro-interactions, enter/exit animations, or any visual detail work. Triggers on UI polish, design details, "make it feel better", "feels off", stagger animations, border radius, optical alignment, font smoothing, tabular numbers, image outlines, box shadows.
Project scaffolding CLI with 30+ integrations, custom templates, and MCP server for AI agents.
Opinionated toolkit for building, versioning, and publishing high-quality JavaScript/TypeScript packages.
Centralized, extensible devtools panel for TanStack libraries with a plugin architecture.
Framework-agnostic debouncing, throttling, rate limiting, queuing, and batching utilities.
Powerful asynchronous state management, server-state utilities, and data fetching for TS/JS, React, Vue, Solid, Svelte & Angular.
基于 SOC 职业分类
| name | tanstack-db |
| description | Reactive client-first store for your API with collections, live queries, and optimistic mutations. |
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 sync