Refine 3.x Chakra UI ShowButton 完整指南:从列表页跳转到详情页的按钮实现与源码剖析
2026/9/14 22:34:37 网站建设 项目流程

Refine 3.x Chakra UI ShowButton 完整指南:从列表页跳转到详情页的按钮实现与源码剖析

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

ShowButton是 Refine 为 Chakra UI 提供的预置导航按钮组件,用于在列表页中将用户重定向到当前记录的详情(show)页面。本文以 Refine 3.xx 版本文档为核心,结合仓库内@pankod/refine-chakra-ui的真实源码与测试用例,系统讲解其用法、recordItemIdresourceNameOrRouteNamehideTextaccessControl等核心属性,并深入剖析其底层基于useNavigationshow方法与useShowButtonhook 的实现原理,帮助你直接复用并可按需 swizzle 定制。

ShowButton 是什么

ShowButton基于 Chakra UI 的<Button>中的show方法完成跳转。它的典型使用场景是:在列表页的"操作"列中,为每一行记录渲染一个"查看详情"按钮,点击后进入/{resource}/show/{id}路由。

从源码实现看(show/index.tsx),ShowButton接收resourcerecordItemIdhideTextaccessControlsvgIconPropsmetachildrenonClick等属性,并将它们传给核心 hookuseShowButton

const { to, label, title, hidden, disabled, LinkComponent } = useShowButton({ resource: resourceNameFromProps, id: recordItemId, accessControl, meta, });

由 hook 计算出的to(目标路由)、label(按钮文案)、title(提示文本)以及hidden/disabled状态,最终决定渲染方式:

  • hideTexttrue时,渲染为只带眼睛图标的IconButton
  • 否则渲染为带IconEye左图标的普通Button,按钮文字为children ?? label(默认即 "Show")。

整个按钮被包裹在LinkComponent(即 routerProvider 提供的链接组件)中,因此点击后走的是 SPA 路由跳转而非整页刷新。

快速上手:在列表页使用 ShowButton

以下示例来自 show.md,展示了如何在基于@pankod/refine-react-table的表格中,为每一行渲染一个ShowButton

import { List, TableContainer, Table, Thead, Tr, Th, Tbody, Td, ShowButton, } from "@pankod/refine-chakra-ui"; import { useTable, ColumnDef, flexRender } from "@pankod/refine-react-table"; const PostList: React.FC = () => { const columns = React.useMemo<ColumnDef<IPost>[]>( () => [ { id: "id", header: "ID", accessorKey: "id", }, { id: "title", header: "Title", accessorKey: "title", }, { id: "actions", header: "Actions", accessorKey: "id", cell: function render({ getValue }) { return <ShowButton recordItemId={getValue() as number} />; }, }, ], [], ); const { getHeaderGroups, getRowModel } = useTable({ columns }); return ( <List> <TableContainer> <Table variant="simple" whiteSpace="pre-line"> <Thead> {getHeaderGroups().map((headerGroup) => ( <Tr key={headerGroup.id}> {headerGroup.headers.map((header) => ( <Th key={header.id}> {!header.isPlaceholder && flexRender( header.column.columnDef.header, header.getContext(), )} </Th> ))} </Tr> ))} </Thead> <Tbody> {getRowModel().rows.map((row) => ( <Tr key={row.id}> {row.getVisibleCells().map((cell) => ( <Td key={cell.id}> {flexRender(cell.column.columnDef.cell, cell.getContext())} </Td> ))} </Tr> ))} </Tbody> </Table> </TableContainer> </List> ); }; interface IPost { id: number; title: string; }

在这个示例中,actions列通过getValue()取出当前行的id,并将其作为recordItemId传给ShowButton。别忘了在<Refine>resources中注册对应的show页面:

const App = () => { return ( <Refine notificationProvider={RefineChakra.notificationProvider()} resources={[ { name: "posts", list: PostList, show: ShowPage, }, ]} /> ); };

基础环境配置

文档中的实时示例依赖以下环境配置:使用RefineReactRouterV6作为 routerProvider,RefineSimpleRest作为 dataProvider,并包裹在RefineChakra.ChakraProviderrefineTheme主题之下:

const { default: routerProvider } = RefineReactRouterV6; const { default: simpleRest } = RefineSimpleRest; setRefineProps({ routerProvider, dataProvider: simpleRest("https://api.fake-rest.refine.dev"), Layout: RefineChakra.Layout, Sider: () => null, catchAll: <RefineChakra.ErrorComponent />, });

核心属性详解

recordItemId

recordItemId用于将记录 id 追加到路由路径的末尾。例如:

<ShowButton colorScheme="black" recordItemId="123" />

点击按钮后会触发useNavigationshow方法,将应用重定向到/posts/show/123

需要特别注意的是,<ShowButton>默认会从路由中读取 id 信息。也就是说,如果你在 show 页面(如/posts/show/1)上渲染<ShowButton />而不传recordItemId,组件会通过useRouterContext().useParams()自动解析当前路由中的id。这一行为在测试用例中也有明确验证(见下文"路由跳转的测试验证")。

resourceNameOrRouteName

重定向端点(resourceNameOrRouteName/show)由resourceNameOrRouteName属性决定。默认情况下,<ShowButton>使用 resource 对象的name属性作为点击后的跳转端点。当需要跳转到其他资源时,可显式指定:

<ShowButton colorScheme="black" resourceNameOrRouteName="categories" recordItemId="2" />

此时点击按钮会触发show方法并跳转到/categories/show/2。对应的resources配置如下:

resources={[ { name: "posts", list: MyShowComponent }, { name: "categories", show: ShowPage }, ]}

hideText

hideText用于控制是否显示按钮文字。当为true时,按钮只显示图标(眼睛图标),适合空间紧凑的表格操作列:

<ShowButton colorScheme="black" recordItemId="123" hideText />

从源码看(show/index.tsx),hideText模式下渲染IconButton,并透传variant="outline"aria-label={label}data-testid等属性,保证无障碍与测试友好。

accessControl

accessControl属性用于控制权限校验行为,仅在向<Refine/>提供了accessControlProvider时生效:

  • enabled:是否跳过权限校验;
  • hideIfUnauthorized:当用户无权限访问该资源时是否隐藏按钮。
import { ShowButton } from "@pankod/refine-chakra-ui"; export const MyListComponent = () => { return ( <ShowButton accessControl={{ enabled: true, hideIfUnauthorized: true }} /> ); };

此外,ShowButton也接受 Chakra UIButton的全部原生属性(colorSchemesizedisabledhiddenonClick等),这些属性通过...rest透传给底层按钮组件。

底层原理:useShowButton 与 useNavigation

useShowButton 的调用链

ShowButton之所以能拿到跳转目标与权限状态,全部依赖核心包中的useShowButtonhook。从 packages/core/src/hooks/button/index.tsx 可以看到,useShowButton只是对通用导航按钮 hook 的封装:

export const useShowButton = ( props: Prettify<Omit<NavigationButtonProps, "action">>, ) => useNavigationButton({ ...props, action: "show" });

即通过action: "show"复用统一的useNavigationButton逻辑,计算路由、权限与文案。类似的还有useEditButtonaction: "edit")、useCloneButtonuseListButton等,这说明 ShowButton 与 EditButton、CloneButton、ListButton 共享同一套导航按钮基础设施。

useNavigation 的 show 方法

ShowButton的跳转行为最终落到useNavigationshow方法上。根据 useNavigation.md 的说明:

const { show } = useNavigation(); show("posts", "1"); // It navigates to the `/posts/show/1` page

show方法接收资源名与记录 id,导航到/{resource}/show/{id}页面;它还支持第三个可选参数typeHistoryType),用于控制 push / replace 等导航行为。此外还有配套的showUrl方法,仅返回 URL 而不执行跳转:

const { showUrl } = useNavigation(); showUrl("posts", "1"); // It returns the `/posts/show/1` URL

这两者的函数签名分别为:

方法说明签名
show跳转到详情页( resource: string, id: BaseKey, type: HistoryType ) => void
showUrl返回详情页 URL( resource: string, id: BaseKey ) => string

路由跳转的测试验证

ShowButton的行为由跨 UI 库共用的测试套件保障。在 packages/ui-tests/src/tests/buttons/show.tsx 中,通过buttonShowTests覆盖了以下关键场景:

  • 默认渲染成功,按钮文案为 "Show" 且未被禁用;
  • 传入disabled后按钮禁用,且点击不会触发onClick
  • 传入hidden后按钮不渲染;
  • 组件带有正确的data-testidRefineButtonTestIds.ShowButton);
  • hideText模式下不渲染文字、只显示图标;
  • 点击按钮触发onClick回调;
  • 路由跳转验证:在列表路由/posts下渲染<ShowButton recordItemId="1" />,点击后链接href/posts/show/1
  • 从详情页读取 id:在/posts/show/1路由下渲染<ShowButton />(不传 id),生成的链接依然是/posts/show/1,印证了"默认从路由读取 id"的行为;
  • 自定义资源跳转<ShowButton resource="categories" recordItemId="1" />生成/categories/show/1

这些测试同时覆盖了 accessControl 的多种组合(全局配置 vs 组件属性、enableAccessControlhideIfUnauthorized、权限拒绝时的禁用与 title 提示等),是理解accessControl语义的第一手资料。Chakra UI 侧的实现只需一行绑定即可接入这套公共测试(show/index.spec.tsx):

import { buttonShowTests } from "@refinedev/ui-tests"; import { ShowButton } from "./"; describe("Show Button", () => { buttonShowTests.bind(this)(ShowButton); });

Swizzle 定制与类型说明

使用 refine CLI 进行 swizzle

原文档标记了swizzle: true,意味着你可以使用refine CLI将该组件复制到自己的项目中进行完全定制(例如改变默认图标、调整按钮文案或包装自定义逻辑)。执行 swizzle 后,组件会以可编辑源码的形式落入你的项目,不再受库版本升级影响。

ShowButtonProps 类型

在 packages/chakra-ui/src/components/buttons/types.ts 中,Chakra UI 版的ShowButtonProps定义如下:

export type ShowButtonProps = Omit< RefineShowButtonProps< ButtonProps, { svgIconProps?: Omit<IconProps, "ref">; } >, "ignoreAccessControlProvider" >;

也就是说,它继承自@refinedev/ui-typesRefineShowButtonProps,泛型参数为 Chakra UI 的ButtonProps,并额外支持svgIconProps(用于定制眼睛图标的大小与样式,源码中默认size={20})。类型中剔除的ignoreAccessControlProvider用于强制接入权限体系。

总结

ShowButton是 Refine 3.x + Chakra UI 项目中"列表 → 详情"导航的标准解法:

  • 开箱即用:无需手写useNavigation().show(...)与路由拼接,一行<ShowButton recordItemId={id} />即可;
  • 智能默认:不传recordItemId时自动从当前路由解析 id,适配列表页与详情页两种使用场景;
  • 权限友好:配合accessControlProvider可实现无权限时禁用(并显示原因)或直接隐藏按钮;
  • 完全可定制:既可通过 Chakra UI 的ButtonProps自由调整外观,也可通过 refine CLI swizzle 获得源码级控制权。

若需深入了解其底层导航机制,可继续阅读 useNavigation 文档、ShowButton 源码、核心 useShowButton hook 以及 公共按钮测试套件。

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

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

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

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

立即咨询