Skip to main content

useData

useData is a lightweight wrapper around React Query that standardizes HTTP calls, adds first-class support for server-side shaping, pagination, and an optional mockData override for editor scenarios. Source: src/api/fetchData.ts

Signature

function useData<T>(
  apiClient: HttpClient,
  url: string | null,
  requestConfig?: {
    method?: 'get' | 'post' | 'put' | 'delete'
    data?: any
    queryConfig?: Partial<QueryObserverOptions<T>>
    shape?: string[]
    page?: number
    size?: number
    mockData?: T
  },
): {
  resource: T | undefined
  hasError: boolean
  isLoading: boolean
  query?: Omit<UseQueryResult<T>, 'data' | 'isError' | 'isLoading'>
}

Behavior

  • Adds _shape=... to the URL when shape is provided (comma-separated fields)
  • Adds page and size if provided
  • Uses React Query to fetch with a stable key that includes:
    • finalUrl, method, data, apiClient.defaults.baseURL, and apiClient.defaults.headers
  • Disables retry for HTTP 401 errors; otherwise retries up to 3 times
  • If mockData is provided, short-circuits and returns it immediately with isLoading: false
Note on caching: headers are part of the query key; token/header changes will revalidate. If you need header-agnostic caching, use useSuspenseFetch with includeHeaders: false.

Examples

GET with shaping and pagination

import { useData } from '@/api/fetchData'
import { useLocationByRouteContext } from '@/states/useLocationByRouteContext'

export function UseDataExample() {
  const { httpClient } = useLocationByRouteContext()
  const { resource, isLoading, hasError } = useData<{ Records: Array<{ Id: number; Name: string }> }>(httpClient, '/api/public/teams/my', {
    shape: ['Records.Id', 'Records.Name'],
    page: 1,
    size: 20,
    queryConfig: { staleTime: 60_000 },
  })

  if (isLoading) return <div>Loading…</div>
  if (hasError) return <div>Failed to load</div>
  return <pre>{JSON.stringify(resource, null, 2)}</pre>
}

POST with payload

const { resource } = useData<{ Success: boolean }>(httpClient, '/api/public/helpdesk/messages', {
  method: 'post',
  data: { subject: 'Printer', message: 'Paper jam on Floor 2' },
})

Editor/mock data

const { resource } = useData(httpClient, '/api/public/faqs', {
  mockData: { FaqArticles: [{ Question: 'Q?', Answer: 'A!' }], OpenAiEnabled: false },
})

Return values

  • resource – The typed response or undefined while loading
  • isLoading – React Query loading flag
  • hasError – React Query error flag (boolean)
  • query – The rest of the React Query result (methods, status) minus the basic fields

Edge cases

  • url is null/falsy → hook is disabled (enabled: false) and no request is made
  • 401 Unauthorized → no retries (fast-fail to let auth state respond)

See also