useQuery runs a query against the LiveStore database and subscribes the component to future updates. The component re-renders whenever the query result changes.
Function signature
queryDb(tables.todos.query), you get back Todo[].
Parameters
The query to run. Accepts any
Queryable<TResult>:- A
LiveQueryDefcreated withqueryDb() - A
SignalDefcreated withsignal() - A
ComputedDefcreated withcomputed() - A SQL
QueryBuilderfrom a table definition
Queryable.Result<TQueryable>.The store instance to query against. Required when calling
useQuery directly from @livestore/react.You do not need to pass this when using store.useQuery() — the store is provided automatically.Return value
The current query result. For
queryDb() queries this is typically T[] or T | undefined depending on the query.
For signals and computed values it is the signal’s current value.The result is synchronously populated on the first render (no loading state needed).Usage
Basic query
Query via the store instance
When you have a store fromuseStore, call store.useQuery() to avoid passing options.store explicitly:
Parameterized query
Pass reactive values into the query definition. React re-creates thequeryDb value when the deps change, and useQuery picks up the new query automatically:
Conditional query
Skip the query entirely by returning a fallback when the condition is false:Querying a signal
useQuery works with signals and computed values as well as SQL queries:
useQueryRef
useQueryRef is the lower-level variant that returns the query result wrapped in a React ref alongside the underlying LiveQuery instance. Use it when you need to access the latest value without triggering an additional render (for example, in event handlers).
Function signature
Parameters
Same as
useQuery.Same as
useQuery.Optional parent OpenTelemetry context for the query span.
Optional explicit span name. Defaults to
LiveStore:useQuery:{label}.Return value
A React ref whose
current always holds the latest query result. Reading valueRef.current inside an event handler gives you the current value without causing a stale closure issue.The underlying reference-counted
LiveQuery instance. This is an implementation detail used by advanced integrations.Example
Do not mutate the result returned by
useQuery or held in valueRef.current. LiveStore shares the result object internally — mutating it can cause reactivity bugs.How reactivity works
Each call touseQuery creates or reuses a reference-counted LiveQuery instance. The query runs synchronously on the first render so there is never a loading flash. LiveStore then subscribes to future updates and calls setValue when the result changes. The component re-renders only if the new value is deeply unequal to the previous one (deepEqual comparison).
When the component unmounts the reference count is decremented. LiveStore disposes the query when the count reaches zero.