Overview
@navios/react-query is a type-safe React Query integration library that bridges TanStack Query v5 with the @navios/builder API client. It provides a declarative, schema-validated approach to handling server state management in React applications.
Package: @navios/react-query
License: MIT
Peer Dependencies: @navios/builder, @tanstack/react-query (^5.51.21), zod (^3.25.0 || ^4.0.0)
Why Use React Query Integration?
Type Safety
End-to-end TypeScript support with automatic type inference:
- Query parameters are typed from your endpoint definitions
- Response data is typed from your Zod schemas
- Mutation variables are type-checked
- Query keys are automatically generated and typed
Automatic Query Key Management
Builder automatically generates hierarchical query keys:
const getUser = client.query({
method: 'GET',
url: '/users/$userId',
responseSchema: userSchema,
processResponse: (data) => data,
})
// Automatic key generation
// Key: ['users', '123']
const key = getUser.queryKey.dataTag({ urlParams: { userId: '123' } })
Suspense Support
First-class React Suspense support:
function UserProfile({ userId }: { userId: string }) {
const user = getUser.useSuspense({ urlParams: { userId } })
// No loading/error checks needed!
return <div>{user.name}</div>
}
Optimistic Updates
Built-in support for optimistic updates with automatic rollback:
const updateUser = client.mutation({
// ...
onMutate: async (variables, context) => {
// Optimistically update UI
context.queryClient.setQueryData(/* ... */)
},
onError: (error, variables, context) => {
// Automatic rollback on error
},
})
Key Principles
- Type-Safe - End-to-end TypeScript support with Zod validation
- Declarative - Define API contracts once, reuse everywhere
- Schema Validation - Request/response validation at runtime
- Smart Invalidation - Hierarchical query key management
- Suspense Ready - First-class React Suspense support
Architecture
Quick Start
// 1. Setup API builder
import { builder } from '@navios/builder'
import { create } from '@navios/http'
import { declareClient } from '@navios/react-query'
import { z } from 'zod'
const api = builder()
api.provideClient(create({ baseURL: 'https://api.example.com' }))
// 2. Create React Query client
const client = declareClient({ api })
// 3. Define schema
const userSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
})
// 4. Create query
const getUser = client.query({
method: 'GET',
url: '/users/$userId',
responseSchema: userSchema,
processResponse: (data) => data,
})
// 5. Use in component
function UserProfile({ userId }: { userId: string }) {
const user = getUser.useSuspense({ urlParams: { userId } })
return <div>{user.name}</div>
}
Features
Queries
Type-safe queries with automatic cache management:
const getUser = client.query({
method: 'GET',
url: '/users/$userId',
responseSchema: userSchema,
processResponse: (data) => data,
})
// Standard hook
const { data, isLoading, error } = getUser.use({ urlParams: { userId: '123' } })
// Suspense hook
const user = getUser.useSuspense({ urlParams: { userId: '123' } })
Infinite Queries
Paginated data with infinite scroll support:
const getUsers = client.infiniteQuery({
method: 'GET',
url: '/users',
querySchema: z.object({
cursor: z.string().optional(),
}),
responseSchema: z.object({
users: z.array(userSchema),
nextCursor: z.string().nullable(),
}),
processResponse: (data) => data,
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
initialPageParam: undefined,
})
Mutations
Type-safe mutations with optimistic updates:
const createUser = client.mutation({
method: 'POST',
url: '/users',
requestSchema: userCreateSchema,
responseSchema: userSchema,
processResponse: (data) => data,
useContext: () => ({ queryClient: useQueryClient() }),
onSuccess: (data, variables, context) => {
context.queryClient.invalidateQueries({ queryKey: ['users'] })
},
})
Query Key Management
Automatic query key generation and invalidation:
// Invalidate specific query
await getUser.invalidate(queryClient, { urlParams: { userId: '123' } })
// Invalidate all matching queries
await getUser.invalidateAll(queryClient, { urlParams: { userId: '123' } })
What's Next?
- Getting Started - Installation and setup
- Queries - Learn about queries
- Mutations - Learn about mutations
- Query Keys - Understand query key management
- Suspense - Use Suspense for cleaner code
- Optimistic Updates - Update UI optimistically