Refine Chakra UI `<RefreshButton>` 详解:重新获取当前记录数据及其源码级实现
2026/9/14 7:11:30 网站建设 项目流程

Refine Chakra UI<RefreshButton>详解:重新获取当前记录数据及其源码级实现

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

Refine 的 Chakra UI 集成包提供了<RefreshButton>组件,它通过点击按钮重新拉取页面当前展示的记录数据,是 Show/Detail 页面上最常见的“刷新”操作入口。本文以官方文档(refresh.md)为主线,完整讲解其用法与全部属性,并结合当前仓库源码深入剖析其底层调用链——包括useRefreshButton钩子如何定位 resource 与 id、loading状态如何从 React Query 查询状态推导,以及点击后如何通过失效(invalidate)机制触发数据重新获取。

它做了什么

<RefreshButton>基于 Chakra UI 的<Button>组件渲染,点击时触发 refine core 提供的useOne数据方法,进而经由dataProvider重新请求指定 resource 下指定 id 的记录,使页面上已缓存/已展示的数据与服务端最新状态保持一致。

组件支持通过 refine CLI 执行 swizzle(swizzle: true)把源码复制到项目内做二次定制,因此了解它的内部实现对你扩展其行为非常关键。

基本用法

在 Show 页面中,把<RefreshButton />放入<Show>headerButtons插槽即可获得右上角的刷新按钮。以下示例注册了posts资源,PostShow通过useShow取数,headerButtons中放置刷新按钮(完整可运行示例见原文档中的 live demo 代码块):

import { useShow } from "@pankod/refine-core"; import { Show, Heading, Text, Spacer, MarkdownField, RefreshButton, } from "@pankod/refine-chakra-ui"; const PostShow: React.FC<IResourceComponentsProps> = () => { const { queryResult } = useShow<IPost>(); const { data, isLoading } = queryResult; const record = data?.data; return ( <Show headerButtons={<RefreshButton />} isLoading={isLoading}> <Heading as="h5" size="sm">Id</Heading> <Text mt={2}>{record?.id}</Text> <Heading as="h5" size="sm" mt={4}>Title</Heading> <Text mt={2}>{record?.title}</Text> <Heading as="h5" size="sm" mt={4}>Content</Heading> <Spacer mt={2} /> <MarkdownField value={record?.content} /> </Show> ); };

配合Refine组件的resources配置(name: "posts",并挂上show: PostShow),导航到/posts/show/123后,点击按钮即会重新请求id123的记录。

属性详解

recordItemId:控制刷新哪条记录

recordItemId决定刷新动作作用于哪条数据。不传时,组件默认从路由中读取:id

import { RefreshButton } from "@pankod/refine-chakra-ui"; const MyRefreshComponent = () => { return <RefreshButton colorScheme="black" recordItemId="123" />; };

此时点击按钮会触发useOne,获取 resource 为"post"(取自路由)、id 为"123"的记录。原文档明确提示:<RefreshButton>默认从路由读取 id 信息,因此显式传入recordItemId是覆盖这一默认行为的手段,适合在列表页等无:id路由参数的位置刷新特定记录。

resourceNameOrRouteName:控制刷新哪个资源

resourceNameOrRouteName决定刷新动作作用于哪个资源。同理,不传时默认从路由解析资源名:

const MyRefreshComponent = () => { return ( <RefreshButton colorScheme="black" resourceNameOrRouteName="categories" recordItemId="2" /> ); };

此时点击按钮会获取 resource 为"categories"、id 为"2"的记录——即按钮所在的资源(posts)与要刷新的资源(categories)可以不同,这在跨资源联动场景(例如在文章详情页刷新关联分类)中非常有用。

hideText:只显示图标

hideText用于控制按钮文字是否展示。设为true时只渲染按钮图标:

const MyRefreshComponent = () => { return <RefreshButton colorScheme="black" hideText recordItemId="123" />; };

从当前仓库的组件源码可以确认其实现方式:hideTexttrue时渲染的是 Chakra UI 的IconButtonaria-label使用翻译后的 label),否则渲染带leftIconButton,见 refresh/index.tsx。

其余 Chakra UI Button 属性

由于RefreshButton的 props 类型是 Chakra UIButtonProps的超集,colorSchemesizeisLoadingclassName等原生属性都会透传(源码中通过{...rest}展开到<Button>/<IconButton>上),文档示例中的colorScheme="black"即由此而来。此外 Chakra UI 版本还支持svgIconProps用于微调内部刷新图标(默认使用@tabler/icons-reactIconRefresh,尺寸 20)。

API Reference(属性一览)

属性类型默认值说明
recordItemIdBaseKey从 URL 的:id读取指定要刷新数据的记录 id
resourceNameOrRouteNamestring从路由推断的资源名指定要刷新的资源
hideTextbooleanfalsetrue时仅显示图标
onClickPointerEventHandler<HTMLButtonElement>自定义点击处理函数,提供后会替代默认刷新逻辑
dataProviderNamestring"default"指定目标 data provider(多 data provider 场景)
childrenReactNodei18n 的"buttons.refresh"(默认"Refresh"按钮文字
svgIconPropsOmit<IconProps, "ref">透传给刷新图标的 SVG 属性(Chakra UI 专属扩展)
...restChakra UIButtonProps透传给底层<Button>/<IconButton>

说明:recordItemId/resourceNameOrRouteName的默认行为与上表基于原文档(v3 版本 API)。在当前仓库源码中,v4 起 props 命名演化为resource/recordItemId,且meta已从类型中移除(见下文实现章节)。

源码级实现剖析

组件层:packages/chakra-ui中的薄封装

当前实现位于 RefreshButton 组件,它本身不写任何取数逻辑,而是把全部行为委托给 core 的useRefreshButton钩子,仅负责 UI 呈现:

const { onClick: onRefresh, label, loading, } = useRefreshButton({ resource: resourceNameFromProps, id: recordItemId, dataProviderName, });

几个值得注意的实现细节:

  • 双形态渲染hideText为真时走IconButton分支(附aria-label={label}),否则走Button分支并以leftIcon挂载刷新图标;两个分支都把variant固定为outline
  • loading 直接驱动按钮isLoading={loading}让 Chakra UI 按钮自动显示 spinner,无需业务侧手动管理。
  • onClick 可被覆盖onClick ? onClick(e) : onRefresh()—— 一旦传入自定义onClick,默认刷新逻辑即被完全取代,这为“刷新前先做前置校验”等定制留了口子。
  • 可测试性:两个分支都注入了data-testid={RefineButtonTestIds.RefreshButton}className={RefineButtonClassNames.RefreshButton}(来自@refinedev/ui-types),供 E2E 与 UI 测试稳定定位。

其 props 类型在 types.ts 中定义为:

export type RefreshButtonProps = RefineRefreshButtonProps< ButtonProps, { svgIconProps?: Omit<IconProps, "ref"> } >;

RefineRefreshButtonProps的通用部分定义在 packages/ui-types/src/types/button.tsx,由RefineButtonCommonProps(含hideText)、RefineButtonResourceProps(含resource,注释明确“默认从路由推断资源名”)、RefineButtonSingleProps(含recordItemId,注释“默认从 URL 读取:id”)、RefineButtonDataProps(含dataProviderName)与RefineButtonLinkingProps(含onClick)组合而成——这正是上文 API 表中各默认行为的类型层依据。

逻辑层:core 中的useRefreshButton

真正的“刷新”逻辑集中在 packages/core/src/hooks/button/refresh-button/index.tsx,三个返回值各有来源:

  1. resource 与 id 的解析:通过useResourceParams({ resource, id })把显式传入的 props 与路由参数合并,路由值作为兜底默认——这就是“默认从路由读取 id / 资源名”的实现出处。
  2. label走国际化translate("buttons.refresh", "Refresh"),接入i18nProvider的应用会自动翻译按钮文字。
  3. loading从 React Query 状态推导
const loading = !!queryClient.isFetching({ queryKey: keys() .data(pickDataProvider(identifier, props.dataProviderName, resources)) .resource(identifier) .action("one") .get(), });

即监听one查询是否处于 fetching 状态,一旦取数开始,按钮自动进入 loading,取数结束自动恢复。

  1. 点击后的动作是“失效”而非直接取数
const onClick = () => { invalidates({ id, invalidates: ["detail"], dataProviderName: props.dataProviderName, resource: identifier, }); };

点击调用useInvalidate使指定 resource/id 的detail类查询失效(stale),由 React Query 自动重新执行对应的one查询并回源到dataProvider。从源码结构看,这与原文档描述的“点击触发useOne重新获取记录”在效果上等价,但机制上已从“按钮直接调用useOne”演进为“失效查询、由缓存层驱动重新取数”——packages/ui-types 的 CHANGELOG 也记录了这次变更:“<RefreshButton />will useuseInvalidatesinstead ofuseOne”,同时metaRefineRefreshButtonProps中弃用。

版本适用提示:本文档主体对应 v3 版 API(resourceNameOrRouteNameuseOne直取);如果你基于当前仓库源码(v4+)开发,props 应写作resource,刷新机制为 invalidatedetail查询。两者的默认行为(从路由读 id 与资源名)保持一致。

测试保障

Chakra UI 的按钮实现并非单独维护用例,refresh/index.spec.tsx 直接绑定@refinedev/ui-tests包的共享用例集:

import { buttonRefreshTests } from "@refinedev/ui-tests"; describe("Refresh Button", () => { buttonRefreshTests.bind(this)(RefreshButton); });

这意味着 refresh 按钮在 Chakra UI、Mantine、Material UI 等各 UI 包中执行同一套行为契约(渲染、点击触发刷新、hideText形态、onClick覆盖等),保证了跨 UI 框架的行为一致性。core 侧同样有对应的 useRefreshButton 测试。

小结与延伸阅读

<RefreshButton>是 Refine “headless 逻辑 + UI 薄封装”架构的典型样本:UI 包(packages/chakra-ui)只负责按钮形态与事件接线,资源/记录的定位、i18n 文案、loading 推导与失效刷新全部沉淀在 core 的useRefreshButton(packages/core/src/hooks/button/refresh-button/index.tsx),并通过@refinedev/ui-types的共享类型与@refinedev/ui-tests的共享用例在多 UI 包间保持一致。常用属性速查:

  • recordItemId="123":刷新指定 id 的记录(默认取路由:id);
  • resourceNameOrRouteName="categories"(v4+ 为resource):刷新其他资源的记录(默认取路由资源名);
  • hideText:仅保留图标的紧凑形态;
  • 透传全部 Chakra UIButton属性,colorScheme="black"等样式写法直接可用。

相关文档:useOne、dataProvider、RefreshButton 原文档。

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

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

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

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

立即咨询