triplit icon indicating copy to clipboard operation
triplit copied to clipboard

[Feature] Conditional Queries

Open daveycodez opened this issue 7 months ago • 2 comments

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.

daveycodez avatar May 20 '25 21:05 daveycodez

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 }
}

daveycodez avatar May 23 '25 01:05 daveycodez

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

daveycodez avatar Jul 29 '25 19:07 daveycodez