Ghostly
Guides

Data Fetching

Using Ghostly with TanStack Query, SWR, Apollo, tRPC, and more.

TanStack Query

import { useQuery } from '@tanstack/react-query'
import { Ghostly } from '@ghostly-ui/react'

function UserCard({ userId }: { userId: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
  })

  return (
    <Ghostly loading={isLoading}>
      <Card user={data} />
    </Ghostly>
  )
}

SWR

import useSWR from 'swr'
import { GhostlyList } from '@ghostly-ui/react'

function BlogIndex() {
  const { data, isLoading } = useSWR('/api/posts', fetcher)

  return (
    <GhostlyList loading={isLoading} count={5} item={<PostPreview />} className="space-y-4">
      {data?.map(post => <PostPreview key={post.id} post={post} />)}
    </GhostlyList>
  )
}

Apollo GraphQL

import { useQuery, gql } from '@apollo/client'

function UserCard({ userId }: { userId: string }) {
  const { data, loading } = useQuery(GET_USER, { variables: { id: userId } })

  return (
    <Ghostly loading={loading}>
      <Card user={data?.user} />
    </Ghostly>
  )
}

tRPC

function ProductPage({ id }: { id: string }) {
  const { data, isLoading } = trpc.product.getById.useQuery({ id })

  return (
    <Ghostly loading={isLoading}>
      <ProductDetail product={data} />
    </Ghostly>
  )
}

Native fetch + useTransition

function SearchResults({ query }: { query: string }) {
  const [results, setResults] = useState(null)
  const [isPending, startTransition] = useTransition()

  useEffect(() => {
    startTransition(async () => {
      const data = await fetch(`/api/search?q=${query}`).then(r => r.json())
      setResults(data)
    })
  }, [query])

  return (
    <Ghostly loading={isPending}>
      <ResultsList results={results} />
    </Ghostly>
  )
}