Because TanStack Query uses a global cache, you can use the same useQuery hook in multiple places without making excess XHR requests.
Traditionally, if you have data on a server, that you want to use in multiple places throughout your component tree, the advice is to lift it to the top and either prop-drill its data or put it in a context. In this contrived example, suppose the <Header> component and the <Dashboard> component both need the data from the primary server fetch. And the <Footer> component needs to know if there was an error fetching that server data:
function App() {
const query = useQuery({
queryKey: ["data"],
queryFn: () => fetchData()
})
return <div>
<Header data={query.data}/>
<Dashboard data={query.data} isPending={query.isPending}/>
<Footer error={query.error}/>
</div>
}
But prop-drilling can be annoying. For example, that <Footer> component might look like this:
function Footer({error}: {error: Error | null}) {
return <footer>
<Alert error={error}/>
<p>Copyright 2026</p>
</footer>
}
function Alert({error}: {error: Error | null}) {
if (error) {
return <div className="footer-error">There was an error fetching the data</div>
}
return null
}
What you can do instead
First, refactor the useQuery call so it becomes a hook that encapsulates any of its configuration. For example:
function useData() {
return useQuery({
queryKey: ["data"],
queryFn: () => fetchData(),
retry: 0,
});
}
Now, you can use that hook in all the places where it's needed. For example:
function Header() {
const {data} = useData();
return <h1>
Page Title {data ? ` (${data.count} items)` : null}
</h1>
}
function Footer() {
return <footer>
<Alert/>
<p>Copyright 2026</p>
</footer>
}
function Alert() {
const {error} = useData()
if (error) {
return <div className="footer-error">There was an error fetching the data</div>
}
return null
}
And in the end, you can remove any drop-drilling
function App() {
return <div>
<Header/>
<Dashboard/>
<Footer/>
</div>
}
Conclusion
The useQuery hook will use the global cache, that probably looks something like this:
import { App } from "./App";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
const app = (
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>
);
And that global cache will recognize if a query has started by the queryKey value. If one such Promise already exists, it won't start another. So you're guaranteed to not make multiple XHR queries to the back end.