00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

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