Introduction
Fetching data from a remote API or database is a core task for most applications.
Cerberus Signals provide foundational primitives like createQuery
and createMutation to manage asynchronous data.
Cerberus Signals data fetching APIs come with the following benefits:
- High performing: our benchmarks outperform Tanstack queries by over 60% in some areas
- Caching: all queries are cached until invalidated
- Optimistic updates: built in support for "real-time" optimistic UI updates
- Data Streaming: compatible with Async Generators for LLM responses
- SSR Sync: fetch data on the server and sync it to a client-side query
- Suspense: native support for React Suspense
- Error Boundaries: native support for Error Boundaries
Fetching Data
To fetch (and cache) data using signals, simply follow two steps:
- Define a query factory via
createQuery - Use the factory via
useQueryin your component
In this example we use a Signal to trigger a new query request. When using this design you, opt-out of optimistic UI updates and fallback to legacy loading-based UI changes.
In this example there are a few things happening:
- The "backend API"
- The query factory
- The component using the query
- An action that updates the global
currentUserstate
When you pass an Signal Accessor into the query definition, it will auto-fetch, invalidate, and cache the result when the signal Accessor updates. This means, with this design mutations are not neccessary - but still strongly recommended.
Optimistically Updating Query Data
When you want to perform an action related to a query, you utilize a mutation factory via createMutation.
When combined with query.key, this factory will automagically sync and update the query if it is listed in the invalidate options.
Even more, when combined with onMutate/onSetData, the UI will optimistically update while the query runs in the background creating a "real-time" like experience in the UI.
Here's what's happening in this demo:
- A query factory is created
- A mutation factory is created
a.
onMutate/setQueryDataprovides optimistic updates to thequeryb.invalidatebreaks thequerycache to ensure the latest data is fetched in the background - The UI is automagically synced with the query data
- Actions call the
mutatehelper to trigger mutations.
Server Component Pattern
In an SSR environment, you execute the factory's raw fetcher directly, bypassing the reactive cache. Then, you pass that data down to your Client Components to "hydrate" or seed the Cerberus cache, ensuring the client doesn't double-fetch on mount.
This is the standard SSR pattern for React.
1. Server Component (Fetching)
Expose the raw, stateless fetcher function from your factory. You simply await it like a standard asynchronous function.
2. Client Component
On the client side, use the initialData property. If the Cerberus cache is empty, it will instantly seed the cache with the server's data, skipping the <Suspense> boundary entirely.
Streaming Reponses (Async Generators)
Cerberus queries also support streaming data via Async Generators. This is powerful if you are using an LLM API or your local API supports data streaming.