Skip to main content

preact-db

Preact bindings for TanStack DB. useLiveQuery hook with query callbacks, { query, queryKey } config objects, or pre-created collections; identity is derived from query IR, with no dependency arrays. Conditional queries via returning undefined/null. useLiveInfiniteQuery for paging an ordered live query. Functional variants (fn.where) require queryKey. Import from @tanstack/preact-db (re-exports all of @tanstack/db).

Source facts

Repository
TanStack/db
Last source activity
October 28, 2026 at 02:19
Detected SKILL.md language
English
Stars
3,978
Forks
278

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
preact-db
description
Preact bindings for TanStack DB. useLiveQuery hook with query callbacks, { query, queryKey } config objects, or pre-created collections; identity is derived from query IR, with no dependency arrays. Conditional queries via returning undefined/null. useLiveInfiniteQuery for paging an ordered live query. Functional variants (fn.where) require queryKey. Import from @tanstack/preact-db (re-exports all of @tanstack/db).
type
framework
library
db
framework
preact
library_version
0.6.17
requires
["db-core"]
sources
["TanStack/db:docs/framework/preact/overview.md","TanStack/db:packages/preact-db/src/useLiveQuery.ts","TanStack/db:packages/preact-db/src/useLiveInfiniteQuery.ts"]
This skill builds on db-core. Read it first for collection setup, query builder, and mutation patterns. Queries read concrete source Collections. Preact has no `DbProvider` yet, so it does not bind collection descriptors or read from a `DbClient`; a query over a descriptor throws when it is consumed. Use `@tanstack/react-db` or `@tanstack/svelte-db` for `DbClient`-based SSR and hydration. # TanStack DB — Preact ## Setup ```tsx import { eq, not, useLiveQuery } from '@tanstack/preact-db' function TodoList() { const { data, isLoading } = useLiveQuery((q) => q .from({ todo: todoCollection }) .where(({ todo }) => not(todo.completed)) .orderBy(({ todo }) => todo.created_at, 'asc'), ) if (isLoading) return <div>Loading...</div> return ( <ul> {data.map((todo) => ( <li key={todo.id}>{todo.text}</li> ))} </ul> ) } ``` `@tanstack/preact-db` re-exports everything from `@tanstack/db`. It supports Preact 10+ and ships ES modules only. ## Hooks ### useLiveQuery ```tsx // Query callback const { data, state, status, isReady, isEnabled } = useLiveQuery((q) => q.from({ todo: todoCollection }), ) // Config object (required for queryKey) const { data } = useLiveQuery({ query: (q) => q.from({ todo: todoCollection }), gcTime: 60_000, }) // Pre-created live query collection const { data } = useLiveQuery(activeTodosCollection) // Disabled until an input exists: data and state are undefined const { data, isEnabled } = useLiveQuery((q) => userId ? q .from({ todo: todoCollection }) .where(({ todo }) => eq(todo.userId, userId)) : undefined, ) ``` `isLoadingError` means the first load failed and there is nothing to show; offer `collection.reload()`. `isCrashed` means local storage broke; only `cleanup({ dependents: true })` and a fresh start recover. After the query is ready, sync problems never change `status`: read `isSyncError` or the `health` tree to show stale-data warnings. There is no `isError`. ### useLiveInfiniteQuery ```tsx const { data, pages, fetchNextPage, hasNextPage, isFetchingNextPage } = useLiveInfiniteQuery( (q) => q .from({ post: postsCollection }) .orderBy(({ post }) => post.createdAt, 'desc'), { pageSize: 20 }, ) ``` The query must include `.orderBy()`. `fetchNextPage()` resolves when the page request settles; a failed page load does not reject or change `status`; it appears as a request error in the returned `health` tree. `getNextPageParam` is rejected. ## Preact-Specific Patterns ### Query identity The hook derives identity from the query IR on every render. Captured values in structured expressions recompile the query when they change, so there is no dependency array: ```tsx function Filtered({ minPriority }: { minPriority: number }) { const { data } = useLiveQuery((q) => q .from({ todo: todoCollection }) .where(({ todo }) => gt(todo.priority, minPriority)), ) return <div>{data.length}</div> } ``` While a hook is mounted, a source Collection ID must keep naming the same Collection object. A different object under a previously read ID throws `SourceCollectionIdReuseError`. ## Common Mistakes ### CRITICAL Using opaque query logic without queryKey Wrong: ```tsx const { data } = useLiveQuery((q) => q .from({ todo: todoCollection }) .fn.where(({ todo }) => todo.text.includes(search)), ) ``` Correct: ```tsx const { data } = useLiveQuery({ queryKey: [todoCollection.id, 'search', search], query: (q) => q .from({ todo: todoCollection }) .fn.where(({ todo }) => todo.text.includes(search)), }) ``` Functional variants (`fn.where`, `fn.select`, `fn.having`) have no stable IR identity, so without `queryKey` the hook throws `UnhashableQueryIRError`. Put every value the function captures into the key. ### HIGH Using === instead of eq() in .where() `.where(({ todo }) => todo.completed === false)` compares a query reference, not a value. Use `eq(todo.completed, false)` or `not(todo.completed)`. ### HIGH Reading data of a disabled query without narrowing A callback that can return `undefined` makes `data` possibly `undefined`. Check `isEnabled` or use `data?.`.
View on GitHub