TanStack Query

使用 TanStack Query 获取状态页 — useQuery 指南

用 useQuery 获取 PulseAPI 状态端点。缓存、焦点重取、定时轮询和 SSE 实时 — 全都在一个带类型的 React Hook 里。

为 TanStack Query 发布状态页的三种方式

选择所需的控制级别 — 零代码、低代码或完全 headless。

托管

添加 TanStack Query 端点,把 CNAME 指向 status.yourdomain.com,完成。5 分钟搞定。

Headless

通过公共 API 在你的 TanStack Query 应用内构建自有 UI,完全掌控设计与品牌。

查看 API

嵌入式徽章

将 SVG 正常运行时间和状态徽章放入 README 或落地页。每 5 分钟自动更新。

把这个 health 端点加入你的 TanStack Query 应用

复制、粘贴、把 PulseAPI 指向 URL。健康时返回 200,降级时返回 503。

app/status/use-status-query.ts
import { useQuery } from '@tanstack/react-query'

interface StatusData {
  page: { title: string; customDomain: string | null }
  overallStatus: 'operational' | 'degraded' | 'down' | 'maintenance' | 'unknown'
  endpoints: Array<{
    id: string
    name: string
    status: string
    uptime24h: number
    avgResponseTime: number
  }>
}

export const useStatusQuery = (slug: string) =>
  useQuery<StatusData>({
    queryKey: ['status', slug],
    queryFn: async () => {
      const r = await fetch(`https://api.pulseapi.tech/status/${slug}`)
      if (!r.ok) throw new Error(`Status ${r.status}`)
      return r.json()
    },
    staleTime: 30_000,
    refetchInterval: 30_000,
    refetchOnWindowFocus: true,
  })

将 staleTime 和 refetchInterval 设置为 30 秒以匹配我们的 SSE 心跳。若想无轮询实现实时更新,将此 Hook 与 /sse/status/:slug 流结合,并在事件到达时用 queryClient.setQueryData 更新缓存。

TanStack Query 应用会出什么故障 — 如何捕获

长时间打开的标签页状态过期

放置整夜的仪表板可能仍显示绿色横幅,而生产实际已宕机。refetchInterval + refetchOnWindowFocus 让缓存保持真实。

重新验证时出现错误内容闪烁

placeholderData + keepPreviousData 可在重取期间继续显示上次良好状态,避免 "operational" 与加载骨架之间闪烁。

嵌套组件导致过多并行请求

多个组件调用 useStatusQuery 本会各自发请求,但 React Query 根据 queryKey 去重,每个 slug 同时只会有一个 in-flight 请求。

Headless 视角

不喜欢我们的状态页? 用 TanStack Query 自己构建。

我们的 API 返回的数据与托管 UI 完全一致。完整 OpenAPI 规范见 api.pulseapi.tech/docs.

components/StatusBanner.tsx — 当 PulseAPI 报告降级或宕机时在应用中展示内联横幅。
import { useStatusQuery } from './use-status-query'

export function StatusBanner({ slug }: { slug: string }) {
  const { data, isLoading, error } = useStatusQuery(slug)

  if (isLoading) return <div className="skeleton" />
  if (error) return null
  if (!data) return null
  if (data.overallStatus === 'operational') return null

  return (
    <a href={`https://${data.page.customDomain}`} className="banner">
      {data.overallStatus === 'down' ? 'Service disruption' : 'Degraded service'}
      {' — '}
      {data.endpoints.filter((e) => e.status !== 'operational').length} affected
    </a>
  )
}

TanStack Query 监控 — FAQ

如何将 useQuery 与 SSE 组合以获得实时更新?

在 useEffect 中打开指向 /sse/status/:slug 的 EventSource,每次事件调用 queryClient.setQueryData(["status", slug], to merge event patches into the existing cache entry。useQuery 订阅者无需轮询即保持最新。

支持 TanStack Query v4 和 v5 吗?

都支持。v4 用 cacheTime,v5 改名为 gcTime。v5 的 isLoading 仅表示 "首次加载";若需任意 in-flight 指示请用 isPending + isFetching。

能用 Next.js 或 Remix 在服务端预取状态吗?

可以。在服务器组件或 loader 中调用 queryClient.prefetchQuery,用 HydrationBoundary (v5) 或 Hydrate (v4) 包裹树并传入 dehydrated state。useStatusQuery Hook 首次渲染从 hydrated 缓存读取,客户端无闪烁。

在 useQuery 中使用组织 API key 安全吗?

不安全 — 任何出现在浏览器 JS 的 key 都是公开的。公共状态端点不需要认证;组织 API key 只在服务器使用。如需认证,通过后端路由 (/api/status) 代理,然后从 useQuery 调用该代理。

5 分钟开始监控你的 TanStack Query 应用

免费套餐,无需信用卡。添加端点,故障时接收告警。