MCPcopy
hub / github.com/TanStack/query / HydrationBoundary

Function HydrationBoundary

packages/react-query/src/HydrationBoundary.tsx:25–108  ·  view source on GitHub ↗
({
  children,
  options = {},
  state,
  queryClient,
}: HydrationBoundaryProps)

Source from the content-addressed store, hash-verified

23}
24
25export const HydrationBoundary = ({
26 children,
27 options = {},
28 state,
29 queryClient,
30}: HydrationBoundaryProps) => {
31 const client = useQueryClient(queryClient)
32
33 const optionsRef = React.useRef(options)
34 optionsRef.current = options
35
36 // This useMemo is for performance reasons only, everything inside it must
37 // be safe to run in every render and code here should be read as "in render".
38 //
39 // This code needs to happen during the render phase, because after initial
40 // SSR, hydration needs to happen _before_ children render. Also, if hydrating
41 // during a transition, we want to hydrate as much as is safe in render so
42 // we can prerender as much as possible.
43 //
44 // For any queries that already exist in the cache, we want to hold back on
45 // hydrating until _after_ the render phase. The reason for this is that during
46 // transitions, we don't want the existing queries and observers to update to
47 // the new data on the current page, only _after_ the transition is committed.
48 // If the transition is aborted, we will have hydrated any _new_ queries, but
49 // we throw away the fresh data for any existing ones to avoid unexpectedly
50 // updating the UI.
51 const hydrationQueue: DehydratedState['queries'] | undefined =
52 React.useMemo(() => {
53 if (state) {
54 if (typeof state !== 'object') {
55 return
56 }
57
58 const queryCache = client.getQueryCache()
59 // State is supplied from the outside and we might as well fail
60 // gracefully if it has the wrong shape, so while we type `queries`
61 // as required, we still provide a fallback.
62 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
63 const queries = state.queries || []
64
65 const newQueries: DehydratedState['queries'] = []
66 const existingQueries: DehydratedState['queries'] = []
67 for (const dehydratedQuery of queries) {
68 const existingQuery = queryCache.get(dehydratedQuery.queryHash)
69
70 if (!existingQuery) {
71 newQueries.push(dehydratedQuery)
72 } else {
73 const hydrationIsNewer =
74 dehydratedQuery.state.dataUpdatedAt >
75 existingQuery.state.dataUpdatedAt ||
76 (dehydratedQuery.promise &&
77 existingQuery.state.status !== 'pending' &&
78 existingQuery.state.fetchStatus !== 'fetching' &&
79 dehydratedQuery.dehydratedAt !== undefined &&
80 dehydratedQuery.dehydratedAt >
81 existingQuery.state.dataUpdatedAt)
82

Callers

nothing calls this directly

Calls 4

useQueryClientFunction · 0.90
hydrateFunction · 0.90
getQueryCacheMethod · 0.80
getMethod · 0.80

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…