QueryClient e Provider
Creare il QueryClient
Il QueryClient e’ l’oggetto centrale che gestisce la cache, le query attive e le configurazioni. Va creato una sola volta e passato al provider:
import { QueryClient } from '@tanstack/react-query'
// Crea un'istanza del client
const queryClient = new QueryClient()
Configurare defaultOptions
Puoi specificare opzioni di default per tutte le query e mutation:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minuti
gcTime: 1000 * 60 * 10, // 10 minuti
retry: 2,
refetchOnWindowFocus: true,
refetchOnMount: true,
refetchOnReconnect: true,
},
mutations: {
retry: 0,
onError: (error) => {
console.error('Mutation fallita:', error)
},
},
},
})
Le opzioni di default si applicano a tutte le query, ma possono essere sovrascritte singolarmente:
// Questa query sovrascrive staleTime e retry
const { data } = useQuery({
queryKey: ['config'],
queryFn: fetchConfig,
staleTime: Infinity, // sovrascrive il default di 5 minuti
retry: false, // sovrascrive il default di 2
})
QueryClientProvider
Il QueryClientProvider utilizza il Context di React per rendere il QueryClient disponibile a tutta l’applicazione:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<Navigation />
<MainContent />
<Footer />
</QueryClientProvider>
)
}
Posizionamento nel Tree
Il provider deve stare il piu’ in alto possibile nell’albero dei componenti, tipicamente nel file di entry point:
// main.tsx o index.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>,
)
Accedere al Client con useQueryClient
All’interno di qualsiasi componente figlio del provider, puoi accedere al QueryClient con l’hook useQueryClient:
import { useQueryClient } from '@tanstack/react-query'
function TodoActions() {
const queryClient = useQueryClient()
const handleRefresh = () => {
// Invalida e rifetch manualmente
queryClient.invalidateQueries({ queryKey: ['todos'] })
}
const handleClearCache = () => {
// Rimuove tutte le query dalla cache
queryClient.clear()
}
const handlePrefetch = async () => {
// Prefetch dati che serviranno dopo
await queryClient.prefetchQuery({
queryKey: ['todos', 'archived'],
queryFn: fetchArchivedTodos,
})
}
return (
<div>
<button onClick={handleRefresh}>Aggiorna</button>
<button onClick={handleClearCache}>Pulisci Cache</button>
<button onClick={handlePrefetch}>Precarica Archivio</button>
</div>
)
}
Metodi Utili del QueryClient
const queryClient = useQueryClient()
// Leggere dati dalla cache senza triggerare un fetch
const todos = queryClient.getQueryData<Todo[]>(['todos'])
// Impostare dati nella cache manualmente
queryClient.setQueryData(['todos'], (old: Todo[] | undefined) => {
return old ? [...old, newTodo] : [newTodo]
})
// Controllare lo stato di una query
const state = queryClient.getQueryState(['todos'])
console.log(state?.dataUpdatedAt) // timestamp ultimo aggiornamento
// Cancellare query in corso
queryClient.cancelQueries({ queryKey: ['todos'] })
// Rimuovere query dalla cache
queryClient.removeQueries({ queryKey: ['old-data'] })
Multiple Clients
In scenari avanzati, potresti aver bisogno di piu’ QueryClient separati, ad esempio per isolare la cache di sezioni diverse dell’app:
const mainClient = new QueryClient({
defaultOptions: {
queries: { staleTime: 1000 * 60 },
},
})
const analyticsClient = new QueryClient({
defaultOptions: {
queries: { staleTime: 1000 * 60 * 30 }, // 30 minuti per analytics
},
})
function App() {
return (
<QueryClientProvider client={mainClient}>
<MainApp />
{/* Sezione analytics con il suo client separato */}
<QueryClientProvider client={analyticsClient}>
<AnalyticsDashboard />
</QueryClientProvider>
</QueryClientProvider>
)
}
I provider annidati funzionano come qualsiasi Context React: il provider piu’ vicino vince. I componenti dentro AnalyticsDashboard useranno analyticsClient, tutti gli altri useranno mainClient.
Attenzione con i Multiple Clients
Quando usi piu’ client, ricorda che:
- Le cache sono completamente separate.
- L’invalidazione su un client non influenza l’altro.
- I DevTools mostrano un solo client alla volta.
// Dentro AnalyticsDashboard, questo usa analyticsClient
const queryClient = useQueryClient()
queryClient.invalidateQueries({ queryKey: ['analytics'] })
// Se vuoi accedere al mainClient da qui, devi passarlo come prop
// oppure usare un Context custom