use-cancelable-query
基于 TanStack Query 的可取消请求 hook,适用于 TanStack Start/Router 生态
适用于 TanStack Query v5+ / TanStack Start / TanStack Router
生态选择
| 生态 | Hook |
|---|---|
| Next.js + SWR | use-cancelable-swr |
| TanStack Start/Router | use-cancelable-query(本页) |
这是什么?
痛点:使用 TanStack Query 时,需要手动处理请求取消、类似 SWR 的 mutate API、以及路由 Loader 预取集成。
方案:封装 useQuery,提供统一的可取消请求接口,并增加类似 SWR 的 mutate 方法,同时支持 TanStack Router 的 Loader 预取。
安装与使用
npx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/use-cancelable-query.jsonyarn dlx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/use-cancelable-query.jsonpnpx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/use-cancelable-query.jsonbunx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/use-cancelable-query.json基础用法
import { useCancelableQuery } from '@/hook/use-cancelable-query'
function ProductList() {
const [{ data, isLoading, error, mutate }] = useCancelableQuery<Product[]>({
url: '/api/products',
key: ['products']
})
if (isLoading) return <p>Loading...</p>
if (error) return <p>Error: {error.message}</p>
return (
<div>
<button onClick={() => mutate()}>刷新数据</button>
<ul>
{data?.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
)
}Mutate API
const [{ mutate }] = useCancelableQuery({ url: '/api/data', key: ['data'] })
// 仅重新验证
await mutate()
// 设置数据并重新验证
await mutate(newData)
// 设置数据但不重新验证
await mutate(newData, { revalidate: false })
// 使用 updater 函数
await mutate((old) => [...old, newItem])TanStack Router 集成
在 Loader 中预取数据,与组件共享缓存:
// src/routes/products/index.tsx
import { createFileRoute } from '@tanstack/react-router'
import { prefetchQuery, useCancelableQuery } from '@/hook/use-cancelable-query'
export const Route = createFileRoute('/products')({
loader: async ({ context }) => {
await prefetchQuery(context.queryClient, {
key: ['products'],
url: '/api/products'
})
},
component: ProductsPage
})
function ProductsPage() {
const [{ data }] = useCancelableQuery<Product[]>({
url: '/api/products',
key: ['products']
})
return <ProductList products={data ?? []} />
}globalMutate
在组件外部或跨组件使 query 失效:
import { globalMutate } from '@/hook/use-cancelable-query'
// 使所有以 'products' 开头的 query 失效
globalMutate(queryClient, (key) => Array.isArray(key) && key[0] === 'products')