Skip to content

useQuery accepts throttleMs and silently discards it #1082

Description

@icole

useQuery accepts throttleMs in its options type but never passes it down, so you always get the 30ms default. Nothing warns.

The options object it builds for useWatchedQuery is just:

{
  reportFetching: options.reportFetching,
  rowComparator: options.rowComparator
}

useWatchedQuery does read hookOptions.throttleMs (in differentialWatch, watch, and updateSettings), so it's only that literal that's missing it.

// types fine, still throttles at 30ms
const { data } = useQuery('SELECT * FROM lists', [], { throttleMs: 200 });

Hit this on @powersync/react@2.0.0, and packages/react/src/hooks/watched/useQuery.ts on main looks the same today. Also reproduced on 1.10.0, so it isn't new.

While I was in there I noticed the hook's options type comes from the callback API rather than the watched-query one:

HookWatchOptions extends Omit<SQLOnChangeOptions, 'signal'>

so tables and triggerImmediate type-check too, and are also dropped. Those two have no equivalent in WatchedQueryOptions so they could never have applied. triggerOnTables — the one that would actually limit trigger tables — isn't on the hook type at all. throttleMs seems to be the only one of the four that's both advertised and implementable. The type lineage might be worth a separate look, though changing it would break anyone passing the dead keys.

Two small things I ran into:

Passing throttleMs isn't entirely inert. checkQueryChanged does JSON.stringify(options) on the raw user options, so changing it between renders flips queryChanged and fires an updateSettings({ throttleMs: undefined }).

useSuspenseQuery is unaffected — QueryStore.getQuery forwards throttleMs properly.

The fix looks like one line:

     options: {
       reportFetching: options.reportFetching,
+      throttleMs: options.throttleMs,
       rowComparator: options.rowComparator
     },

Workaround for anyone who finds this first, since both exports are public:

const lists = db.query({ sql, parameters }).differentialWatch({ rowComparator, throttleMs: 200 });
const { data } = useWatchedQuerySubscription(lists);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions