01 Software

React Query

Data fetching and caching with React hooks

React Query

The SDK integrates TanStack Query to provide data fetching, caching, and synchronization.

Setup

npm install @tanstack/react-query

Pass the SDK's client.queryClient to the QueryClientProvider.

lib/software/query-provider.tsx
'use client'

import { QueryClientProvider } from '@tanstack/react-query'
import { client } from './client'

export function QueryProvider({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={client.queryClient}>
      {children}
    </QueryClientProvider>
  )
}

Read Hooks

HookDescription
useQueryList query
useSuspenseQuerySuspense list query
useQueryByIdSingle item query by ID
useSuspenseQueryByIdSuspense single item query
useInfiniteQueryInfinite scroll
useSuspenseInfiniteQuerySuspense infinite scroll

useQuery

const { data, isLoading, error } = client.query.useQuery(
  {
    collection: 'products',
    options: {
      limit: 10,
      where: { status: { equals: 'published' } },
      sort: '-createdAt',
    }
  },
  {
    // TanStack Query options (optional)
    staleTime: 5 * 60 * 1000,
    enabled: true,
  }
)

// data: T[] (docs array)

useQueryById

const { data: product, isLoading } = client.query.useQueryById({
  collection: 'products',
  id: 'product_id',
})

// data: T (document object)

useInfiniteQuery

const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage,
} = client.query.useInfiniteQuery({
  collection: 'products',
  pageSize: 20,
})

// data.pages: T[][] (array per page)

Suspense Hooks

useSuspenseQuery, useSuspenseQueryById, and useSuspenseInfiniteQuery accept the same parameters, with data always available (the enabled option is not supported).

Mutation Hooks

HookDescriptionCache Invalidation
useCreateCreate documentlist cache
useUpdateUpdate documentall cache
useRemoveDelete documentall cache

useCreate

const { mutate: create, isPending } = client.query.useCreate({
  collection: 'products',
})

create(
  { title: 'New Product', price: 10000 },
  {
    onSuccess: (data) => console.log('Created:', data.doc.id),
    onError: (error) => console.error(error),
  }
)

useUpdate

const { mutate: update } = client.query.useUpdate({
  collection: 'products',
})

update({ id: 'product_id', data: { title: 'Updated Product' } })

useRemove

const { mutate: remove } = client.query.useRemove({
  collection: 'products',
})

remove('product_id')

Prefetching (SSR)

// Prefetch in server components
await client.query.prefetchQuery({ collection: 'products', options: { limit: 10 } })
await client.query.prefetchQueryById({ collection: 'products', id: 'product_id' })
await client.query.prefetchInfiniteQuery({ collection: 'products', pageSize: 20 })
app/products/page.tsx
import { HydrationBoundary, dehydrate } from '@tanstack/react-query'

export default async function ProductsPage() {
  await client.query.prefetchQuery({
    collection: 'products',
    options: { limit: 10 }
  })

  return (
    <HydrationBoundary state={dehydrate(client.queryClient)}>
      <ProductList />
    </HydrationBoundary>
  )
}

Cache Management

// Invalidation
client.query.invalidateQueries('products')           // All
client.query.invalidateQueries('products', 'list')   // List only
client.query.invalidateQueries('products', 'detail') // Detail only

// Cache read/write
client.query.getQueryData('products', 'list', options)
client.query.setQueryData('products', 'detail', '123', updatedProduct)

Customer Hooks

React Query hooks for customer authentication. Available on BrowserClient only.

useCustomerMe

Fetches the authenticated customer's profile. Automatically disabled when not authenticated.

const { data: profile, isLoading } = client.query.useCustomerMe()

// data: CustomerProfile | null

useCustomerLogin

const { mutate: login, isPending } = client.query.useCustomerLogin({
  onSuccess: (data) => console.log('Logged in:', data.customer.name),
})

login({ email: 'user@example.com', password: 'password' })
// Automatically invalidates useCustomerMe cache

useCustomerRegister

const { mutate: register } = client.query.useCustomerRegister()

register({ name: 'John', email: 'john@example.com', password: 'secure123' })

useCustomerLogout

const { mutate: logout } = client.query.useCustomerLogout()

logout()
// Removes all customer queries from cache

Other Customer Mutations

HookParamsCache
useCustomerForgotPasswordemail: string
useCustomerResetPassword{ token, password }
useCustomerVerifyEmailtoken: stringInvalidates me
useCustomerChangePassword{ currentPassword, newPassword }
useCustomerRefreshTokenoptions?Invalidates me

Customer Cache Utilities

client.query.invalidateCustomerQueries()  // Invalidate all customer queries
client.query.getCustomerData()            // Read cached profile
client.query.setCustomerData(profile)     // Write cached profile

On this page