[Feature] Conditional Queries
As of right now there is no way to have a query only run given certain conditions. I've created a custom useQuery wrapper that provides a solution in React, it would be great if the official useQuery hook in React could support this:
import type {
Models,
SchemaQuery,
SubscriptionOptions,
SubscriptionSignalPayload,
TriplitClient
} from "@triplit/client"
import type { WorkerClient } from "@triplit/client/worker-client"
import { createStateSubscription } from "@triplit/react"
import { useCallback, useMemo, useState, useSyncExternalStore } from "react"
export function useConditionalQuery<M extends Models<M>, Q extends SchemaQuery<M>>(
client: TriplitClient<M> | WorkerClient<M>,
query?: Q | false | null | "" | 0,
options?: Partial<SubscriptionOptions> & { disabled?: boolean }
) {
const stringifiedQuery = !options?.disabled && query && JSON.stringify(query)
const localOnly = !!options?.localOnly
const defaultValue: SubscriptionSignalPayload<M, Q> = {
results: undefined,
fetching: true,
fetchingLocal: false,
fetchingRemote: false,
error: undefined
}
// biome-ignore lint/correctness/useExhaustiveDependencies:
const [subscribe, snapshot] = useMemo(
() =>
stringifiedQuery
? createStateSubscription(client, query, options)
: [() => () => {}, () => defaultValue],
[stringifiedQuery, localOnly]
)
const getServerSnapshot = useCallback(() => snapshot(), [snapshot])
return useSyncExternalStore(subscribe, snapshot, getServerSnapshot)
}
This allows you to pass false-y values as query or to specify disabled in the options. It works like a charm, when the query is disabled it simply does nothing, doesn't even create the subscription. I'd love if the official useQuery hook had this implementation. This is how the SWR and TS Query DX is for handling conditional queries.
Here is useConditionalQueryOne if anyone needs it
type useConditionalQueryOnePayload<M extends Models<M>, Q extends SchemaQuery<M>> = Omit<
SubscriptionSignalPayload<M, Q>,
"results"
> & { result: FetchResult<M, Q, "one"> }
export function useConditionalQueryOne<M extends Models<M>, Q extends SchemaQuery<M>>(
client: TriplitClient<M> | WorkerClient<M>,
query?: Q | false | null | "" | 0,
options?: Partial<SubscriptionOptions> & { disabled?: boolean }
): useConditionalQueryOnePayload<M, Q> {
const { fetching, fetchingLocal, fetchingRemote, results, error } = useConditionalQuery(
client,
query ? ({ ...query, limit: 1 } as Q) : query,
options
)
const result = useMemo(() => {
return results?.[0] ?? null
}, [results])
return { fetching, fetchingLocal, fetchingRemote, result, error }
}
This has been added via { enabled } option but I'd still love to be able to pass false-y values to query for simpler DX