Refine 数据获取进阶:useShow Hook 完整指南——从基础用法到源码级原理
2026/9/10 22:45:36 网站建设 项目流程

Refine 数据获取进阶:useShow Hook 完整指南——从基础用法到源码级原理

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

useShow是 Refine(@refinedev/core)中用于获取单条记录的核心数据 Hook,它在useOne的基础之上扩展而来,能够自动从当前 URL 中解析resourceid并调用 data provider 的getOne方法。本文以 useShow 官方文档为主体,结合 useShow 源码实现 与 测试用例,完整讲解其全部属性、返回值、实时更新机制与底层调用链,帮助你写出可复用、可维护的记录详情页。

useShow 是什么

useShowuseOne的扩展版本,支持useOne的全部特性并在此基础上增加了从 URL 自动推断资源与 id的能力。它的典型应用场景是「详情页 / Show 页面」:当用户导航到/products/show/123这样的路由时,useShow会自动读取路径中的resourceproducts)与id123),并作为参数传给 data provider 的getOne方法。

从源码注释可以看到它的定位(packages/core/src/hooks/show/index.ts):

useShowhook allows you to fetch the desired record. It usesgetOnemethod as query function from the dataProvider that is passed to<Refine>.

在 Refine v5 中,useShow已经完成了从 v4 时代返回结构(queryResult包裹data)到扁平化返回结构result直接持有记录、query持有查询状态)的演进,这也是官方文档所展示的推荐用法。

基础用法:渲染一个产品详情页

useShow默认不接收任何属性,它会尝试从当前 URL 中读取resourceid。以下示例来自 官方基础用法 Live Preview,演示了一个最小可用的产品详情页:

import { useShow } from "@refinedev/core"; interface IProduct { id: number; name: string; material: string; } const ProductShow: React.FC = () => { const { result: product, query: { isFetching, isError, refetch }, } = useShow<IProduct>(); if (isFetching) { return <div>Loading...</div>; } if (isError) { return <div>Something went wrong!</div>; } return ( <div> <h3>Product Details</h3> <p>id: {product?.id}</p> <p>name: {product?.name}</p> <p>material: {product?.material}</p> <button onClick={refetch}>Refresh</button> </div> ); };

配套的路由与资源声明如下(live preview 中通过setRefineProps注入):

setRefineProps({ resources: [ { name: "products", show: "/products/show/:id", }, ], }); // 路由挂载 <ReactRouter.Routes> <ReactRouter.Route path="/products/show/:id" element={<ProductShow />} /> </ReactRouter.Routes>

这个示例覆盖了useShow三个关键用法:

  • 自动推断参数:无需手动传入resourceid,Hook 从/products/show/123中解析出products123
  • 扁平化返回值result直接就是记录对象(product?.id),而query是 TanStack Query 的查询结果,可解构出isFetchingisErrorrefetch等状态与方法;
  • 手动刷新:通过query.refetch()重新触发getOne请求。

如果你显式地在 Hook 上定义resourceid,那么当这些属性发生变化时,useShow自动触发一次新的请求(详见后文源码分析)。

属性(Properties)详解

resource

resource用于指定要获取记录的资源名称,默认从当前 URL 读取。手动指定时:

useShow({ resource: "categories", });

需要注意:一旦手动传入resource,URL 中的id将被忽略——因为该id可能属于其他资源。此时应使用useParsed从 URL 中取出id再传入:

import { useShow, useParsed } from "@refinedev/core"; const { id } = useParsed(); useShow({ resource: "custom-resource", id, });

也可以不传id,改用返回的setShowId函数在运行时设置:

import { useShow } from "@refinedev/core"; const { setShowId } = useShow({ resource: "custom-resource", }); setShowId("123");

当多个资源同名时,可传入identifier而非资源nameidentifier只作为资源匹配的主键,data provider 的方法仍然使用<Refine/>组件中定义的资源name来调用(参见 useShow 源码 中resource: identifier的传参方式)。

id

id决定要获取哪一条记录,会被作为参数传给 data provider 的getOne方法。默认从当前 URL 读取:

useShow({ id: 123, });

从 类型定义 可以看到id的类型是BaseKey(即string | number,并支持泛型约束):

export type UseShowProps<...> = { resource?: string; // @default 从 URL 读取 :resource id?: BaseKey; // @default 从 URL 读取 :id ... };

meta

meta是一个特殊属性,用于向 data provider 方法传递附加信息,主要有两个用途:

  • 针对特定用例定制 data provider 方法;
  • 使用纯 JavaScript 对象(JSON)生成 GraphQL 查询。

例如,通过meta传递自定义请求头,并在自定义 data provider 的getOne中消费它:

useShow({ meta: { headers: { "x-meta-data": "true" }, }, }); const myDataProvider = { //... getOne: async ({ resource, id, meta }) => { const headers = meta?.headers ?? {}; const url = `${apiUrl}/${resource}/${id}`; const { data } = await httpClient.get(`${url}`, { headers }); return { data }; }, //... };

从源码看,useShow通过useMeta将资源定义(resource definition)、URL 查询参数与 Hook 传入的meta合并后再传给useOne(packages/core/src/hooks/show/index.ts)。这一点在 测试用例 中得到了直接验证:测试同时注入资源定义meta: { dip: "dop" }、URL 参数baz: "qux"与 Hook 参数foo: "bar",断言getOne最终收到的meta三者俱全。

dataProviderName

当项目中配置了多个 data provider 时,用dataProviderName指定使用哪一个:

useShow({ dataProviderName: "second-data-provider", });

源码类型注释中明确其默认值为"default"(packages/core/src/hooks/show/types.ts),该值最终会传给useOne,用于通过useDataProvider解析出正确的 provider 实例。

queryOptions

queryOptions用于向底层的 TanStack QueryuseQuery透传额外选项:

useShow({ queryOptions: { retry: 3, enabled: false, }, });

值得注意的底层细节:useShow在内部会对queryOptions做一次合并且强制设置enabled(packages/core/src/hooks/show/index.ts):

const queryResult = useOne<TQueryFnData, TError, TData>({ resource: identifier, id: showId ?? "", queryOptions: { enabled: showId !== undefined, ...queryOptions, }, ... });

也就是说,当showId尚未确定(例如 URL 中没有 id、也未通过 prop 传入)时,查询会被禁用;当showId被设置后,查询自动启用。因此,传入的queryOptions.enabled会覆盖这一默认行为,需要谨慎使用。

successNotification 与 errorNotification

这两个属性需要NotificationProvider配合使用。数据获取成功/失败后,useShow会调用NotificationProvideropen函数展示通知,你可以用这两个属性自定义通知内容:

useShow({ successNotification: (data, values, resource) => { return { message: `${data.title} Successfully fetched.`, description: "Success with no errors", type: "success", }; }, });
useShow({ errorNotification: (data, values, resource) => { return { message: `Something went wrong when getting ${data.id}`, description: "Error", type: "error", }; }, });

从源码类型看,UseShowProps混入了SuccessErrorNotification<GetOneResponse<TData>, TError, Prettify<{ id?: BaseKey } & MetaQuery>>类型(packages/core/src/hooks/show/types.ts),即通知回调的第二个参数(values)为{ id } & meta的合并对象。实际通知触发逻辑由useOne内部的useHandleNotification完成。

实时更新相关:liveMode、onLiveEvent、liveParams

以下三个属性均需要LiveProvider才能生效:

  • liveMode:决定收到相关 live 事件时是自动("auto")还是手动("manual")更新数据,用于在应用中实时更新并展示数据:
useShow({ liveMode: "auto", });
  • onLiveEvent:订阅到新事件时的回调函数:
useShow({ onLiveEvent: (event) => { console.log(event); }, });
  • liveParams:传给LiveProvidersubscribe方法的参数。

在 Hook 挂载时,useShow(经由useOne内部的useResourceSubscription)会以channelresource等参数调用liveProvider.subscribe,从而订阅实时更新;卸载时相应取消订阅。这些 live 相关 props 通过...useOneProps透传(packages/core/src/hooks/show/index.ts)。

overtimeOptions

用于处理请求耗时过长的场景,interval为回调间隔毫秒数,onInterval为每个间隔触发的函数。配合返回值中的overtime对象(elapsedTime为已耗时的毫秒数,请求完成后变为undefined):

const { overtime } = useShow({ //... overtimeOptions: { interval: 1000, onInterval(elapsedInterval) { console.log(elapsedInterval); }, }, }); console.log(overtime.elapsedTime); // undefined, 1000, 2000, 3000 4000, ... // 典型用法:超时提示 { overtime.elapsedTime >= 4000 && <div>this takes a bit longer than expected</div>; }

底层由useLoadingOvertimeHook 实现,useShow将其返回的overtime原样透出(packages/core/src/hooks/show/types.ts 中UseShowReturnTypeUseLoadingOvertimeReturnType交叉)。

返回值(Return Values)

属性说明
queryTanStack QueryuseQuery的完整返回值(QueryObserverResult<{ data: TData; error: TError }>),包含isFetchingisErrorrefetchisSuccessdata
result解构后的记录数据(TData),为query.data?.data的便捷别名,undefined表示尚未获取成功
showId当前useShow正在使用的id
setShowIdshowId的 setter,类型为Dispatch<SetStateAction<BaseKey \| undefined>>,调用后会触发一次新的数据请求
overtime超时加载信息,{ elapsedTime?: number }

从 类型定义 可以确认queryresult的关系:

export type UseShowReturnType<TData, TError> = { query: QueryObserverResult<GetOneResponse<TData>, TError>; result: TData | undefined; showId?: BaseKey; setShowId: React.Dispatch<React.SetStateAction<BaseKey | undefined>>; } & UseLoadingOvertimeReturnType;

setShowId的典型场景是基于用户交互切换详情对象(例如列表点击、轮播切换等),源码实现中将setShowId直接指向useResourceParams返回的setId

const { resource, identifier, id: showId, setId: setShowId, } = useResourceParams({ id, resource: resourceFromProp });

实时更新(Realtime Updates)

useShow挂载时,它会调用liveProvidersubscribe方法并传入channelresource等参数;这样当该记录在服务端发生变化时,客户端可以收到实时事件并更新界面。结合liveMode: "auto"即可实现「无需刷新页面,数据自动更新」的体验。完整的 LiveProvider 配置与liveMode语义参见 Live / Realtime 文档。

源码级实现:useShow 的完整调用链

从 packages/core/src/hooks/show/index.ts 的完整实现可以看到useShow的四个核心步骤:

  1. 解析资源与 id:调用useResourceParams({ id, resource: resourceFromProp }),从 URL 或 props 中解析出resourceidentifierid(即showId)与setId(即setShowId)。这是「从 URL 自动推断」能力的来源;

  2. 合并 meta:调用useMeta()生成getMeta,把资源定义、URL 参数与 Hook 传入的meta合并为combinedMeta

  3. 兜底告警:当显式传入resourceshowId缺失时,通过warnOnce输出一条警告,提示用户应使用setShowId或显式传入id,否则useShow无法从 URL 推断 id(警告信息源码);

  4. 委托给 useOneuseShow本身不直接调用useQuery,而是把解析结果与全部透传属性交给useOne,由useOne完成真正的查询:

    • 通过useDataProviderdataProviderName解析 data provider 实例;
    • 调用 data provider 的getOne作为查询函数;
    • 通过useResourceSubscription完成实时订阅;
    • 通过useHandleNotification触发成功/失败通知;
    • 通过useLoadingOvertime实现超时检测;
    • 最终基于 TanStack Query 的useQuery返回QueryObserverResult

这也是为什么文档将其定义为「useOne的扩展版本」:所有useOne的能力(meta、dataProviderName、通知、实时、超时)在useShow中都被完整保留,useShow额外提供的只是 URL 推断与showId状态管理。

测试验证:行为如何被保证

packages/core/src/hooks/show/index.spec.tsx 中的测试用例直接印证了上述行为:

  • 从 URL 读取 id:使用mockRouterProvider({ action: "show", id: "1", pathname: "/posts/show/1" }),直接调用useShow()即可成功获取posts[0],且showId === "1"(对应测试 "correctly return id value from route");
  • 从 props 读取参数useShow({ resource: "posts", id: "1" })useShow({ resource: "categories", id: "2" })均能正确返回对应的showId与数据;
  • 资源与路由不一致时的行为:当路由是/posts/show/1却传入resource: "categories"(不带 id)时,showIdundefined(URL 中的 id 被忽略),印证了文档中「显式传入 resource 会忽略 URL id」的约定;
  • setShowId 动态切换:先断言默认showId === "1",再调用result.current.setShowId("3"),断言showId更新为"3",且更新 prop 会触发重新请求;
  • meta 合并:断言资源定义、URL 查询参数与 Hook 参数的 meta 会一并传递给getOne

API 参考

Props

  • resource?: string——资源名称,默认读取 URL 中的:resource
  • id?: BaseKey——记录 id,默认读取 URL 中的:id
  • queryOptions?: MakeOptional<UseQueryOptions<...>, "queryKey" | "queryFn">——TanStack QueryuseQuery选项;
  • meta?: MetaQuery——传给 data providergetOne的附加元数据;
  • dataProviderName?: string——目标 data provider 名称,默认"default"
  • successNotification/errorNotification——自定义成功/失败通知(需NotificationProvider);
  • liveMode?: "auto" | "manual" | "off"——实时更新模式,默认"off"
  • onLiveEvent?: (event) => void——实时事件回调;
  • liveParams?: LiveParams——传给liveProvider.subscribe的参数;
  • overtimeOptions?: { interval: number; onInterval?: (elapsedInterval) => void }——超时检测选项。

类型参数(Type Parameters)

属性说明类型默认值
TQueryFnData查询函数返回的数据类型,需继承BaseRecordBaseRecordBaseRecord
TError自定义错误对象,需继承HttpErrorHttpErrorHttpError
TDataselect函数返回的数据类型,需继承BaseRecord;未指定时默认取TQueryFnDataBaseRecordTQueryFnData

返回值

属性说明类型
query单条记录查询的结果QueryObserverResult<{ data: TData; error: TError }>
result记录数据TData \| undefined
showId记录 idBaseKey
setShowIdshowId的 setterDispatch<SetStateAction<BaseKey \| undefined>>
overtime超时加载信息{ elapsedTime?: number }

小结

useShow是 Refine 中编写详情页的推荐入口:它继承useOne的全部数据获取能力(getOne、meta 合并、多 provider、通知、实时订阅、超时检测),并在此基础上通过useResourceParams实现 URL 参数自动推断与showId状态管理。理解其「委托useOne+ 扁平化返回」的实现方式,有助于你在自定义详情页、跨资源展示和实时场景中写出更精准的代码。更多相关概念可继续阅读 useOne 文档 与 LiveProvider 文档。

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询