Skip to content

Release v21.19.3

Choose a tag to compare

@github-actions github-actions released this 19 Aug 08:14
1e4750f

Summary

Handing a useQuery hook an object-typed argument that is created in render position — a Guid, a DateOnly, or any generated concept, e.g. Guid.parse(useParams().id) — put the page into an unbounded request loop. useQuery derived its subscribe-effect dependency from raw argument values, and React compares dependencies with Object.is, so two equal-but-distinct Guids re-ran the effect on every render. Each turn aborted the in-flight request and settled a newly constructed result object, which guaranteed the next render, so the loop sustained itself at hundreds of requests per second — enough to stop the tab responding to input and to leave a page permanently stuck in its loading state.

No consumer change is needed: arguments are now compared by serialized value, so an unmemoized Guid can be handed to a query hook in render position safely. This is the same treatment the observable hooks received in #1962; the three sibling hooks (useObservableQuery, useSuspenseQuery, useSuspenseObservableQuery) already serialized their arguments, and useQuery was the odd one out.

Fixed

  • useQuery and useQueryWithPaging no longer re-subscribe on every render when a query argument is an object such as a Guid, a DateOnly, or a generated concept — arguments are compared by serialized value instead of by reference identity (#2584)

Changed

  • serializeArgsForDependency moved out of useObservableQuery into its own module so every query hook derives its argument dependency the same way (#2584)