npm install @tanstack/react-query
import {
QueryClient, QueryClientProvider
} from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* ... */}
</QueryClientProvider>
);
}
function Gallery() {
const { data: images, isLoading, error }
= useQuery({
queryKey: ['images'],
queryFn: () => api('/api/images'),
});
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage
message={error.message} />;
return (
<div className="grid grid-cols-4 gap-4 p-4">
{images.map(img =>
<ImageCard key={img._id} image={img} />
)}
</div>
);
}
function useDeleteImage() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (imageId) =>
api(`/api/images/${imageId}`,
{ method: 'DELETE' }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['images']
}); // Refetch gallery
},
});
}
// Usage in component:
const deleteImage = useDeleteImage();
<button onClick={() =>
deleteImage.mutate(image._id)}>
Delete
</button>
Navigate away from gallery and back — data loads instantly from cache. Delete an image — gallery automatically refetches. No manual state management.
git switch -c refactor/PIXELCRAFT-049-react-query
git add src/
git commit -m "Migrate to React Query, remove fetch boilerplate (PIXELCRAFT-049)"
git push origin refactor/PIXELCRAFT-049-react-query
# PR → Review → Merge → Close ticket ✅
Caching strategies.
Stale-while-revalidate: show cached data immediately (fast), then refetch in the background (fresh).