AutoFetchDataAdapter
import { AutoFetchDataAdapter } from '@signaldb/core'Fetches a query's items from a remote source the first time that query is registered, and drops them again a while after nothing is watching it any more.
Use it for data you want to pull on demand rather than synchronise in full. This is the successor to v1's AutoFetchCollection; see the upgrade guide if you are migrating from it.
If you want the whole collection kept in step with a server instead, you want @signaldb/sync.
Usage
import { Collection, AutoFetchDataAdapter } from '@signaldb/core'
const dataAdapter = new AutoFetchDataAdapter({
fetchQueryItems: async (collectionName, selector) => {
const response = await fetch(`/api/${collectionName}?q=${encodeURIComponent(JSON.stringify(selector))}`)
return response.json()
},
})
const Posts = new Collection('posts', dataAdapter)
// Registering this query is what triggers the fetch.
const cursor = Posts.find({ authorId: 'user1' })Options
new AutoFetchDataAdapter(options: {
fetchQueryItems: (
collectionName: string,
selector: Selector<BaseItem>,
) => Promise<BaseItem[] | undefined>
storage?: (name: string) => StorageAdapter<any, any>
id?: string
onError?: (error: Error) => void
registerRemoteChange?: (onChange: () => Promise<void>) => Promise<void>
mergeItems?: <T>(a: T, b: T) => T
purgeDelay?: number
})fetchQueryItems: Retrieves the items matching a selector from the remote source. Required. It resolves to an array of items, each of which must carry anid. Resolving toundefined— or anything that is not an array — counts as a failed fetch: the queries for that selector are put into the error state andonErroris called.storage: Called once per collection with the collection's name, and returns the storage adapter fetched items are cached in. Optional: without it, the fetched items are cached in memory and do not survive a reload.id: A logical name, handy when several adapters run side by side.onError: Called when a fetch fails.registerRemoteChange: Called once at construction. Invoke the callback it hands you whenever the remote source changed and every active query should be re-fetched — a websocket message, a server-sent event.mergeItems: How a freshly fetched item is merged with the one already held. Default is a shallow spread with the fresh item winning.purgeDelay: Milliseconds to wait after a query becomes inactive before its items are purged.0purges immediately. Default10000.
The result is not there yet
The fetch happens after the query is registered, so the cursor serves its neutral empty result until the answer arrives — and an empty result is a legitimate answer, which makes the two indistinguishable. Use Cursor#isLoading():
const cursor = Posts.find({ authorId: 'user1' })
effect(() => {
if (cursor.isLoading()) return renderSpinner()
renderPosts(cursor.fetch())
})purgeDelay
Items fetched for a query are dropped purgeDelay milliseconds after the last cursor on that query goes away. The delay exists because navigating away from a view and back again is common, and re-fetching what you had a second ago is waste.
Raise it if your users move between views quickly. Lower it, or set it to 0, if holding the data costs more than fetching it again.