React Query v5 Hooks

Only on Invokix

Invokix is the only tool that generates React Query v5 hooks from your API contract. Every endpoint becomes a production-ready, fully typed hook — with proper query keys, error handling, and cache invalidation built in.

What gets generated

For every GET endpoint, Invokix generates a useQuery hook. For every POST, PUT, PATCH, and DELETE endpoint, it generates a useMutation hook. Every hook is typed against the schemas in your contract.

Generated: src/hooks/useOrders.ts
// Auto-generated by Invokix — do not edit manually
// Contract: Orders API v1.2 — published March 5, 2025

import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import type { Order, CreateOrderBody } from "@/types/orders"

export const orderKeys = {
all: ["orders"] as const,
list: () => [...orderKeys.all, "list"] as const,
detail: (id: string) => [...orderKeys.all, "detail", id] as const,
}

export function useGetOrders() {
return useQuery({
  queryKey: orderKeys.list(),
  queryFn: async (): Promise<Order[]> => {
    const res = await fetch("/api/orders")
    if (!res.ok) throw new Error("Failed to fetch orders")
    return res.json()
  },
})
}

export function useGetOrder(orderId: string) {
return useQuery({
  queryKey: orderKeys.detail(orderId),
  queryFn: async (): Promise<Order> => {
    const res = await fetch("/api/orders/" + orderId)
    if (!res.ok) throw new Error("Failed to fetch order")
    return res.json()
  },
  enabled: !!orderId,
})
}

export function useCreateOrder() {
const queryClient = useQueryClient()
return useMutation({
  mutationFn: async (body: CreateOrderBody): Promise<Order> => {
    const res = await fetch("/api/orders", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    })
    if (!res.ok) throw new Error("Failed to create order")
    return res.json()
  },
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: orderKeys.list() })
  },
})
}

export function useCancelOrder() {
const queryClient = useQueryClient()
return useMutation({
  mutationFn: async (orderId: string): Promise<void> => {
    const res = await fetch("/api/orders/" + orderId, { method: "DELETE" })
    if (!res.ok) throw new Error("Failed to cancel order")
  },
  onSuccess: (_data, orderId) => {
    queryClient.invalidateQueries({ queryKey: orderKeys.list() })
    queryClient.removeQueries({ queryKey: orderKeys.detail(orderId) })
  },
})
}

Using the generated hooks

Drop the hooks directly into your components. Every hook is fully typed — no manual type annotations needed.

OrderList.tsx
import { useGetOrders, useCreateOrder, useCancelOrder } from "@/hooks/useOrders"
import type { CreateOrderBody } from "@/types/orders"

export function OrderList() {
const { data: orders, isLoading, error } = useGetOrders()
const createOrder = useCreateOrder()
const cancelOrder = useCancelOrder()

if (isLoading) return <Spinner />
if (error) return <ErrorMessage />

return orders?.map((order) => (
  <OrderCard
    key={order.id}
    order={order}
    onCancel={() => cancelOrder.mutate(order.id)}
  />
))
}

Query key structure

Every generated hook uses a structured query key factory — orderKeys.all, orderKeys.list(), orderKeys.detail(id). This means cache invalidation always works correctly. When you create or update an order, the list cache invalidates automatically. When you cancel an order, both the list and the detail cache for that specific order are cleared.

You never need to manage query keys manually.

Requirements

React Query v5 must be installed in your project:

Terminal
pnpm add @tanstack/react-query

Wrap your app in a QueryClientProvider:

app/layout.tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"

const queryClient = new QueryClient()

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
  <html>
    <body>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </body>
  </html>
)
}

Next steps