UNPKG

@tanstack/react-db

Version:

React integration for @tanstack/db

67 lines (63 loc) • 2.37 kB
import { useEffect, useRef } from 'react' import { createEffect, prepareLiveQueryValue } from '@tanstack/db' import { useOptionalDbClient } from './DbProvider' import { getPreparedSources } from './source-id-bindings' import type { EffectConfig } from '@tanstack/db' /** * React hook for creating a reactive effect that fires handlers when rows * enter, exit, or update within a query result. * * The effect is created on mount and disposed on unmount. If `deps` change, * the previous effect is disposed and a new one is created. * * @example * ```tsx * function ChatComponent() { * useLiveQueryEffect( * { * query: (q) => q.from({ msg: messages }).where(({ msg }) => eq(msg.role, 'user')), * skipInitial: true, * onEnter: async (event) => { * await generateResponse(event.value) * }, * }, * [] * ) * * return <div>...</div> * } * ``` */ export function useLiveQueryEffect< TRow extends object = Record<string, unknown>, TKey extends string | number = string | number, >(config: EffectConfig<TRow, TKey>, deps: React.DependencyList = []): void { const client = useOptionalDbClient() const configRef = useRef<EffectConfig<TRow, TKey>>(config) configRef.current = config useEffect(() => { const query = prepareLiveQueryValue(config.query, client) if (!client) getPreparedSources(query, client, `useLiveQueryEffect`) const effect = createEffect<TRow, TKey>({ id: config.id, query: query as EffectConfig<TRow, TKey>[`query`], skipInitial: config.skipInitial, onEnter: (event, ctx) => configRef.current.onEnter?.(event, ctx), onUpdate: (event, ctx) => configRef.current.onUpdate?.(event, ctx), onExit: (event, ctx) => configRef.current.onExit?.(event, ctx), onBatch: (events, ctx) => configRef.current.onBatch?.(events, ctx), onError: config.onError ? (error, event) => configRef.current.onError?.(error, event) : undefined, onSourceError: config.onSourceError ? (error) => configRef.current.onSourceError?.(error) : undefined, }) return () => { // React cannot await cleanup. Report a failed source release. void effect.dispose().catch((error) => { console.error(`[useLiveQueryEffect] failed to dispose effect:`, error) }) } }, [...deps, client]) }