From 74676283fd7a5128aec9e3b334429c9e1ecd4268 Mon Sep 17 00:00:00 2001 From: Scott Cooper Date: Tue, 18 Aug 2026 13:22:35 -0700 Subject: [PATCH] perf(react-query): Batch hydration notifications Hydrating several observed queries schedules a separate notification flush for each query. Wrap each HydrationBoundary hydrate pass in a notifyManager transaction so those callbacks flush together. Co-Authored-By: Codex --- .changeset/faster-react-hydration.md | 5 +++++ packages/react-query/src/HydrationBoundary.tsx | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/faster-react-hydration.md diff --git a/.changeset/faster-react-hydration.md b/.changeset/faster-react-hydration.md new file mode 100644 index 00000000000..a515d8ce080 --- /dev/null +++ b/.changeset/faster-react-hydration.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-query': patch +--- + +Batch query notifications during hydration to reduce update scheduling overhead. diff --git a/packages/react-query/src/HydrationBoundary.tsx b/packages/react-query/src/HydrationBoundary.tsx index 901c8e9686c..f0fddd5e309 100644 --- a/packages/react-query/src/HydrationBoundary.tsx +++ b/packages/react-query/src/HydrationBoundary.tsx @@ -1,7 +1,7 @@ 'use client' import * as React from 'react' -import { hydrate } from '@tanstack/query-core' +import { hydrate, notifyManager } from '@tanstack/query-core' import { useQueryClient } from './QueryClientProvider' import type { DehydratedState, @@ -92,7 +92,9 @@ export const HydrationBoundary = ({ // It's actually fine to call this with queries/state that already exists // in the cache, or is older. hydrate() is idempotent for queries. // eslint-disable-next-line react-hooks/refs - hydrate(client, { queries: newQueries }, optionsRef.current) + notifyManager.batch(() => { + hydrate(client, { queries: newQueries }, optionsRef.current) + }) } if (existingQueries.length > 0) { return existingQueries @@ -103,7 +105,9 @@ export const HydrationBoundary = ({ React.useEffect(() => { if (hydrationQueue) { - hydrate(client, { queries: hydrationQueue }, optionsRef.current) + notifyManager.batch(() => { + hydrate(client, { queries: hydrationQueue }, optionsRef.current) + }) } }, [client, hydrationQueue])