Skip to content

Conversation

@TkDodo
Copy link
Collaborator

@TkDodo TkDodo commented Nov 11, 2025

There are two places where the eslint-plugin-query was disabled because of debouncing, but there are two ways to fix this rather than working around it: inlining the queryKey or using the queryFunctionContext.

@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Nov 11, 2025
Comment on lines +86 to +92
const queryResult = useQuery({
queryKey: useDebouncedValue(
useMemo(
() => ['global-dashboard-filters-tag-values', tag, selection, searchQuery],
[tag, selection, searchQuery]
)
),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a limitation of the eslint plugin - it doesn’t track the usage through multiple hooks. The easiest way is to just inline the hook calls, which is fine - it doesn’t violate the rules of hooks as they are all still called top-level.

we can do this if we don’t need the debounced intermediate value anywhere else.

Comment on lines -368 to +377
() => ['search-query-builder-tag-values', queryParams],
() => ['search-query-builder-tag-values', queryParams] as const,
[queryParams]
);
const queryKey = useDebouncedValue(baseQueryKey);
const isDebouncing = baseQueryKey !== queryKey;

// TODO(malwilley): Display error states
const {data, isFetching} = useQuery<string[]>({
// disable exhaustive deps because we want to debounce the query key above
// eslint-disable-next-line @tanstack/query/exhaustive-deps
const {data, isFetching} = useQuery({
queryKey,
queryFn: () => getTagValues(...queryParams),
queryFn: ctx => getTagValues(...ctx.queryKey[1]),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here, we need the debounced key to calculate isDebouncing, so we can’t inline it. What we can do though is not rely on closures for the key, but use the provided queryFunctionContext: React Query gives you the QueryKey into the queryFn so that you can build self-contained functions.

To do this, we need to make sure types flow through correctly so we need:

  • as const on the actual key, otherwise it’s not a tuple
  • remove useQuery<string[]> to just useQuery. using <> is a type assertion in disguise and destroys type inference for the other 3 type parameters useQuery has, so please never do this unless absolutely necessary. Here, getTagValues already returns a Promise<string>, so type inference works nicely and with that, we also get type inference back for the queryFunctionContext. That means we can now access queryParams as ctx.queryKey[1].

@codecov
Copy link

codecov bot commented Nov 11, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
12411 1 12410 10
View the top 1 failed test(s) by shortest run time
BalanceChangeAction re-enables form after error
Stack Traces | 0.147s run time
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name `/submit/i`

There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the `hidden` option to `true`. Learn more about this here: https://testing-library..../docs/dom-testing-library/api-queries#byrole

Ignored nodes: comments, script, style
...
    at Object.getElementError (.../sentry/node_modules/.pnpm/@testing-library+dom@10.4.0/node_modules/@.../dom/dist/config.js:37:19)
    at .../sentry/node_modules/.pnpm/@testing-library+dom@10.4.0/node_modules/@.../dom/dist/query-helpers.js:76:38
    at .../sentry/node_modules/.pnpm/@testing-library+dom@10.4.0/node_modules/@.../dom/dist/query-helpers.js:52:17
    at .../sentry/node_modules/.pnpm/@testing-library+dom@10.4.0/node_modules/@.../dom/dist/query-helpers.js:95:19
    at Object.getByRole (.../gsAdmin/components/changeBalanceAction.spec.tsx:181:33)
    at runNextTicks (node:internal/process/task_queues:65:5)
    at listOnTimeout (node:internal/timers:549:9)
    at processTimers (node:internal/timers:523:7)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@TkDodo TkDodo marked this pull request as ready for review November 11, 2025 09:58
@TkDodo TkDodo requested a review from a team as a code owner November 11, 2025 09:58
() => ['global-dashboard-filters-tag-values', tag, selection, searchQuery],
[tag, selection, searchQuery]
)
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Wrong Key, Wrong Data Cache Mismatch

The queryFn uses the non-debounced searchQuery from closure while the queryKey uses the debounced value. This mismatch causes React Query to cache results under the wrong key - the query executes with the current searchQuery value but gets stored under a key containing the debounced value, potentially returning stale or incorrect cached data.

Fix in Cursor Fix in Web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean yeah, but wasn’t this the case before, too?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants