forked from TanStack/db
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseLiveQueryEffect.ts
More file actions
59 lines (56 loc) · 1.88 KB
/
useLiveQueryEffect.ts
File metadata and controls
59 lines (56 loc) · 1.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { useEffect, useRef } from 'react'
import { createEffect } from '@tanstack/db'
import type { Effect, 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 configRef = useRef<EffectConfig<TRow, TKey>>(config)
configRef.current = config
useEffect(() => {
const effect: Effect = createEffect<TRow, TKey>({
id: config.id,
query: config.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 () => {
// Fire-and-forget disposal; AbortSignal cancels in-flight work
effect.dispose()
}
}, deps)
}