tanstack query

TanStack Query (React Query)

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tanstack query" with this command: npx skills add oriolrius/pki-manager-web/oriolrius-pki-manager-web-tanstack-query

TanStack Query (React Query)

Expert assistance with TanStack Query - Powerful data fetching for React.

Overview

TanStack Query manages server state in React:

  • Caching: Automatic caching and background updates

  • Refetching: Smart refetch strategies

  • Mutations: Optimistic updates and cache invalidation

  • DevTools: Built-in development tools

  • TypeScript: Full TypeScript support

Installation

npm install @tanstack/react-query npm install --save-dev @tanstack/react-query-devtools

Setup

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60 * 1000, // 1 minute cacheTime: 5 * 60 * 1000, // 5 minutes refetchOnWindowFocus: false, }, }, });

function App() { return ( <QueryClientProvider client={queryClient}> <YourApp /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> ); }

useQuery

import { useQuery } from '@tanstack/react-query';

function CertificateList() { const { data, isLoading, error } = useQuery({ queryKey: ['certificates'], queryFn: () => fetch('/api/certificates').then(res => res.json()), });

if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>;

return ( <ul> {data.map(cert => ( <li key={cert.id}>{cert.subject}</li> ))} </ul> ); }

Query with Parameters

function CertificateDetail({ id }: { id: string }) { const { data: certificate } = useQuery({ queryKey: ['certificate', id], queryFn: () => fetch(/api/certificates/${id}).then(res => res.json()), });

return <div>{certificate?.subject}</div>; }

Dependent Queries

function Certificate({ id }: { id: string }) { const { data: certificate } = useQuery({ queryKey: ['certificate', id], queryFn: () => fetchCertificate(id), });

// Only run if certificate exists const { data: ca } = useQuery({ queryKey: ['ca', certificate?.caId], queryFn: () => fetchCA(certificate.caId), enabled: !!certificate?.caId, });

return <div>{ca?.subject}</div>; }

useMutation

import { useMutation, useQueryClient } from '@tanstack/react-query';

function CreateCertificate() { const queryClient = useQueryClient();

const mutation = useMutation({ mutationFn: (newCert) => { return fetch('/api/certificates', { method: 'POST', body: JSON.stringify(newCert), }); }, onSuccess: () => { // Invalidate and refetch queryClient.invalidateQueries({ queryKey: ['certificates'] }); }, });

return ( <button onClick={() => mutation.mutate({ subject: 'CN=example.com' })} disabled={mutation.isPending} > {mutation.isPending ? 'Creating...' : 'Create Certificate'} </button> ); }

Optimistic Updates

const mutation = useMutation({ mutationFn: updateCertificate, onMutate: async (newCert) => { // Cancel outgoing refetches await queryClient.cancelQueries({ queryKey: ['certificates'] });

// Snapshot previous value
const previousCerts = queryClient.getQueryData(['certificates']);

// Optimistically update
queryClient.setQueryData(['certificates'], (old) =>
  old.map((cert) =>
    cert.id === newCert.id ? newCert : cert
  )
);

return { previousCerts };

}, onError: (err, newCert, context) => { // Rollback on error queryClient.setQueryData(['certificates'], context.previousCerts); }, onSettled: () => { // Refetch after success or error queryClient.invalidateQueries({ queryKey: ['certificates'] }); }, });

Pagination

function CertificateList() { const [page, setPage] = useState(1);

const { data, isLoading } = useQuery({ queryKey: ['certificates', page], queryFn: () => fetchCertificates(page), keepPreviousData: true, // Keep old data while fetching new });

return ( <> <ul> {data?.certificates.map(cert => ( <li key={cert.id}>{cert.subject}</li> ))} </ul>

  &#x3C;button onClick={() => setPage(p => p - 1)} disabled={page === 1}>
    Previous
  &#x3C;/button>
  &#x3C;button onClick={() => setPage(p => p + 1)} disabled={!data?.hasMore}>
    Next
  &#x3C;/button>
&#x3C;/>

); }

Infinite Queries

import { useInfiniteQuery } from '@tanstack/react-query';

function InfiniteCertificates() { const { data, fetchNextPage, hasNextPage, isFetchingNextPage, } = useInfiniteQuery({ queryKey: ['certificates'], queryFn: ({ pageParam = 1 }) => fetchCertificates(pageParam), getNextPageParam: (lastPage, pages) => lastPage.nextCursor, initialPageParam: 1, });

return ( <> {data?.pages.map((page, i) => ( <div key={i}> {page.certificates.map(cert => ( <div key={cert.id}>{cert.subject}</div> ))} </div> ))}

  &#x3C;button
    onClick={() => fetchNextPage()}
    disabled={!hasNextPage || isFetchingNextPage}
  >
    {isFetchingNextPage ? 'Loading...' : 'Load More'}
  &#x3C;/button>
&#x3C;/>

); }

Cache Invalidation

const queryClient = useQueryClient();

// Invalidate all queries queryClient.invalidateQueries();

// Invalidate specific query queryClient.invalidateQueries({ queryKey: ['certificates'] });

// Invalidate query with params queryClient.invalidateQueries({ queryKey: ['certificate', '123'] });

// Invalidate all queries starting with key queryClient.invalidateQueries({ queryKey: ['certificates'], exact: false });

// Remove query from cache queryClient.removeQueries({ queryKey: ['certificates'] });

// Reset query to initial state queryClient.resetQueries({ queryKey: ['certificates'] });

Manual Cache Updates

// Set query data queryClient.setQueryData(['certificate', '123'], newCertificate);

// Update query data queryClient.setQueryData(['certificates'], (old) => old.map((cert) => cert.id === '123' ? updated : cert) );

// Get query data const certificates = queryClient.getQueryData(['certificates']);

// Prefetch query await queryClient.prefetchQuery({ queryKey: ['certificate', '123'], queryFn: () => fetchCertificate('123'), });

Best Practices

  • Query Keys: Use arrays for structured keys ['certificates', { status: 'active' }]

  • Stale Time: Set appropriate stale time for your data

  • Cache Time: Keep data in cache longer than stale time

  • Optimistic Updates: Improve UX with optimistic updates

  • Error Handling: Handle errors gracefully

  • Invalidation: Invalidate related queries on mutations

  • Pagination: Use keepPreviousData for better UX

  • DevTools: Use DevTools for debugging

  • TypeScript: Define types for query data

  • Prefetching: Prefetch data for better performance

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

trpc

No summary provided by upstream source.

Repository SourceNeeds Review
General

keycloak

No summary provided by upstream source.

Repository SourceNeeds Review
General

next.js

No summary provided by upstream source.

Repository SourceNeeds Review
General

sqlite

No summary provided by upstream source.

Repository SourceNeeds Review