Prompt
Ensure React hooks and query integrations remain correct across renders, SSR/hydration, and subscriptions.
Rules: 1) Keep QueryClient stable in React components
- Create it once using one of:
React.useState(() => new QueryClient()),React.useMemo(() => new QueryClient(), []), or a lazyuseRefinitializer. - Avoid
new QueryClient()directly in component render. - In Server Components, creating a new
QueryClientper request is fine.
2) Don’t break subscription/snapshot invariants
- Avoid reading refs (or mutating derived values) during render for SyncExternalStore/getSnapshot-style logic.
- If you need “latest filters/options”, update a ref in
useEffect, and read the real source of truth inside the correct React lifecycle (e.g.,getSnapshot) rather than during render.
3) Hydration-safe first render
- Make the initial/optimistic state that React renders match the server render.
- If stale data requires a refetch, trigger it after the first render/mount to prevent hydration mismatches.
4) Use supported disabling patterns
- If you want to disable conditionally, prefer
skipTokenover returning/defining a queryFn that will error whileenabled: falsepatterns would otherwise spam logs.
Example (stable QueryClient + latest filters ref pattern):
import React from 'react'
import { QueryClient } from '@tanstack/react-query'
export function App() {
const [queryClient] = React.useState(() => new QueryClient())
// ...useQuery hooks using queryClient
return null
}
And for “latest value” without render-time ref reads:
const [state, setState] = React.useState(() => client.isFetching(initialFilters))
const filtersRef = React.useRef(filters)
React.useEffect(() => {
filtersRef.current = filters
}, [filters])
// Ensure the snapshot/getter reads in the right lifecycle, not during render-time ref reads.