Data Hooks
All data hooks are powered by TanStack Query v6 with automatic caching, background refetch, and optimistic updates.
Type Safety
Section titled “Type Safety”All data hooks use <TData extends BaseRecord> generics for type-safe data access:
import type { BaseRecord } from '@svadmin/core';
interface Post extends BaseRecord { id: number; title: string; status: 'draft' | 'published';}
// TData is inferred as Postconst query = useList<Post>({ resource: 'posts' });If you register a ResourceTypeMap, hooks auto-infer types and validate resource names at compile time.
Query Hooks
Section titled “Query Hooks”All query hooks accept either static options or a getter function for reactive options:
// StaticuseList({ resource: 'posts', filters: [{ field: 'status', operator: 'eq', value: 'published' }] });
// Reactive getter — re-fetches when $state changesuseList(() => ({ resource: 'posts', pagination, sorters, filters }));useList
Section titled “useList”const query = useList<Post>({ resource: 'posts', pagination: { current: 1, pageSize: 10 } });// query.data → { data: Post[], total: number }useOne
Section titled “useOne”const query = useOne<Post>({ resource: 'posts', id: 1 });// query.data → { data: Post }useShow (alias for useOne)
Section titled “useShow (alias for useOne)”const query = useShow<Post>({ resource: 'posts', id: 1 });useMany
Section titled “useMany”const query = useMany<Post>({ resource: 'posts', ids: [1, 2, 3] });// query.data → { data: Post[] }useSelect
Section titled “useSelect”const query = useSelect({ resource: 'categories', optionLabel: 'name', optionValue: 'id', defaultValue: [1, 2], // pre-selected values searchField: 'name', // server-side search debounce: 300, // search debounce (ms)});// query.options → [{ label: 'Tech', value: '1' }, ...]// query.onSearch → (value: string) => voiduseInfiniteList
Section titled “useInfiniteList”const query = useInfiniteList<Post>({ resource: 'posts', pageSize: 20 });// query.fetchNextPage() — loads the next page// query.hasNextPage — booleanuseCustom
Section titled “useCustom”const query = useCustom<{ stats: number[] }>({ url: '/api/dashboard/stats', method: 'get',});// query.data → { data: { stats: number[] } }useApiUrl
Section titled “useApiUrl”const apiUrl = useApiUrl(); // → 'https://api.example.com'Mutation Hooks
Section titled “Mutation Hooks”useCreate
Section titled “useCreate”const mutation = useCreate<Post>();mutation.mutate({ resource: 'posts', variables: { title: 'Hello' } });useUpdate
Section titled “useUpdate”const mutation = useUpdate<Post>();mutation.mutate({ resource: 'posts', id: 1, variables: { title: 'Updated' } });useDelete
Section titled “useDelete”const mutation = useDelete();mutation.mutate({ resource: 'posts', id: 1 });useCustomMutation
Section titled “useCustomMutation”const mutation = useCustomMutation();mutation.mutate({ url: '/api/posts/publish', method: 'post', values: { ids: [1, 2] } });Bulk: useCreateMany, useUpdateMany, useDeleteMany
Section titled “Bulk: useCreateMany, useUpdateMany, useDeleteMany”Same pattern with arrays of items.
useInvalidate
Section titled “useInvalidate”Manually invalidate cached queries:
const invalidate = useInvalidate();invalidate({ resource: 'posts', invalidates: ['list', 'one'] });Mutation Modes
Section titled “Mutation Modes”All mutation hooks support three modes via mutationMode:
| Mode | Behavior |
|---|---|
pessimistic | Wait for server response (default) |
optimistic | Update UI immediately, rollback on error |
undoable | Show undo toast, delay server call by undoableTimeout ms |
const mutation = useUpdate({ mutationMode: 'undoable', undoableTimeout: 5000 });