Refine MUI RefreshButton 完全指南基于 useInvalidate 的页面数据刷新实现与定制【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读RefreshButton是 Refine 为 Material UIMUI集成提供的内置操作按钮之一它的核心职责是点击后通过useInvalidatehook 使当前页面已缓存的查询失效并重新拉取从而把手动刷新数据这一操作封装成一个开箱即用、可定制、带加载态反馈的按钮组件。本文将以 RefreshButton 官方文档 为骨架结合仓库内 MUI 按钮实现、core 层useRefreshButtonhook、useInvalidate实现 以及对应测试用例完整讲解其用法、全部属性、底层调用链与定制方式。读完本文你将掌握如何在 Show/Edit 等详情页、列表页甚至自定义工具栏中正确使用刷新按钮并理解其失效缓存 → 重新获取的内部机制。组件概览一个按钮如何完成刷新RefreshButton底层渲染的是 Material UI 的Button具体到实现实际使用的是mui/lab的LoadingButton以便支持加载态它并不直接发起任何数据请求而是通过useInvalidatehook 让 Refine 内部的 React Query 缓存失效触发对应查询重新执行点击 RefreshButton │ ▼ useRefreshButtoncore 层 │ 通过 useResourceParams 解析 resource / id ▼ useInvalidate({ resource, id, invalidates: [detail], ... }) │ 依据 dataProviderName 构造查询 key ▼ queryClient.invalidateQueries(queryKey) ──► 重新拉取该条记录的详情数据这条链路中三个关键角色分别为MUI 层RefreshButton负责渲染、图标/文本切换、加载态展示并透传 MUIButton的全部属性core 层useRefreshButton负责解析资源与记录 id、生成点击逻辑、加载态判定与国际化文本core 层useInvalidate真正执行查询 key 的失效操作。快速上手在 Show 页面加入刷新按钮最典型的应用场景是把刷新按钮放进Show详情页组件的headerButtons中。以下示例来自官方文档完整展示了在 Refine v5 MUI 项目中如何使用import { useShow } from refinedev/core; import { Show, RefreshButton } from refinedev/mui; import { Typography, Stack } from mui/material; const PostShow: React.FC () { const { result: post, query } useShowIPost(); const { data, isLoading } query; return ( Show isLoading{isLoading} headerButtons{ RefreshButton / } Typography fontWeightboldId/Typography Typography{post?.id}/Typography Typography fontWeightboldTitle/Typography Typography{post?.title}/Typography /Show ); }; interface IPost { id: number; title: string; }配套的路由与资源定义如下注意show路由中包含:id参数这是RefreshButton能自动推断记录 id 的前提RefineMuiDemo resources{[ { name: posts, list: /posts, show: /posts/show/:id, }, ]} ReactRouter.Routes ReactRouter.Route path/posts element{ div style{{ padding: 16 }} ReactRouter.Outlet / /div } ReactRouter.Route index element{divList page here.../div} / ReactRouter.Route pathshow/:id element{PostShow /} / /ReactRouter.Route /ReactRouter.Routes /RefineMuiDemo运行后详情页头部会渲染出一个带有刷新图标的 Refresh 按钮。点击它会触发useInvalidate随后重新获取当前这条posts记录的数据。从源码层面看这里无需传任何参数的自动推断能力来自useRefreshButton内部调用的useResourceParamsconst { identifier, id, resources } useResourceParams({ resource: props.resource, id: props.id, });当不显式传入resource与recordItemId时它们会从当前路由参数中推断出来——这正是它零配置可用的原因。对应类型定义中也明确标注了默认行为resource默认从路由推断见 ui-types 中RefineButtonResourcePropsrecordItemId默认读取 URL 中的:id见 ui-types 中RefineButtonSingleProps。属性详解PropertiesrecordItemId指定要刷新哪条记录recordItemId用于控制刷新目标记录的 id。默认情况下它会从路由参数中推断例如/posts/show/123中的123。在非详情页例如列表页的自定义工具栏中你可以显式指定import { RefreshButton } from refinedev/mui; const MyRefreshComponent () { return ( RefreshButton resourceposts recordItemId123 / ); };点击该按钮后useInvalidate会针对 resource 为posts、id 为123的单条记录详情查询发起失效并重新获取。resource指定要刷新的资源resource用于控制刷新哪个资源的查询。默认同样从路由推断。下面的例子显式指定刷新categories资源下的123号记录import { RefreshButton } from refinedev/mui; const MyRefreshComponent () { return ( RefreshButton resourcecategories recordItemId123 / ); };需要特别说明的是同名资源identifier场景如果你在Refine/中配置了多个名称相同的资源可以传入资源的identifier来代替name。此时identifier仅作为资源匹配的主键数据提供器data provider的方法仍然使用Refine/组件中定义的资源name工作。详细说明可参考identifier相关文档。这一点在useRefreshButton的源码中得到了印证useResourceParams返回的是identifier而非name随后useInvalidate以identifier作为资源键构造查询 key而数据请求仍走资源本身的nameconst { identifier, id, resources } useResourceParams({ ... }); // ... invalidates({ id, invalidates: [detail], dataProviderName: props.dataProviderName, resource: identifier, });hideText只显示图标hideText用于控制是否隐藏按钮文本。设为true时按钮只显示图标适合放在紧凑的工具栏或表格行操作列中import { RefreshButton } from refinedev/mui; const MyRefreshComponent () { return ( RefreshButton resourceposts recordItemId123 hideText / ); };dataProviderName多数据源时指定提供器当项目配置了多个 data provider 时可通过dataProviderName指定刷新动作作用于哪个数据提供器。该属性定义在 ui-types 的RefineButtonDataProps中并贯穿useRefreshButton→useInvalidate的整个调用链最终用于pickDataProvider决策与查询 key 构造。svgIconProps 与 startIcon自定义图标这是 MUI 集成层独有的扩展属性定义在 packages/mui 的按钮类型。svgIconProps用于给默认刷新图标RefreshOutlined传参如颜色、尺寸startIcon则可完全替换默认图标。实现代码中两者有明确的优先级关系const defaultIcon RefreshOutlined fontSizesmall {...svgIconProps} /; const buttonStartIcon hideText ? undefined : startIcon ?? RefreshOutlined {...svgIconProps} /; const buttonChildren hideText ? startIcon ?? defaultIcon : children ?? label;也就是说当提供startIcon时它优先于默认的RefreshOutlined图标children则优先于默认的 Refresh 文本。底层原理useRefreshButton 与 useInvalidate 的实现剖析core 层useRefreshButton按钮逻辑的真正来源MUI 的RefreshButton本质上是薄封装全部业务逻辑都来自 core 层的useRefreshButton。它返回三个值返回值含义实现说明onClick点击处理函数调用useInvalidate失效目标记录的detail查询label按钮文本通过useTranslate读取 i18n 键buttons.refresh缺省回退为Refreshloading加载态标志通过queryClient.isFetching()检测该记录详情查询是否正在请求中其中loading的实现非常巧妙——它并非常规的点击后置 loading而是实时监测 React Query 的 fetching 状态const loading !!queryClient.isFetching({ queryKey: keys() .data(pickDataProvider(identifier, props.dataProviderName, resources)) .resource(identifier) .action(one) .get(), });只要目标资源的one单条详情查询正在请求中按钮就自动进入加载态。这意味着即使刷新动作由其他组件触发例如useShow初次加载按钮也会同步展示加载中状态并在请求结束后自动恢复。useInvalidate查询 key 与失效范围点击刷新按钮最终落到useInvalidate。RefreshButton传入的是invalidates: [detail]即只针对单条详情查询case detail: return queryClient.invalidateQueries({ queryKey: queryKey .action(one) .id(id || ) .get(), ...invalidationFilters, // 默认 { type: all, refetchType: active } ...invalidationOptions, // 默认 { cancelRefetch: false } });关键默认值说明invalidationFilters默认{ type: all, refetchType: active }匹配该 key 下所有查询变体且只自动重新拉取当前处于激活状态页面可见的查询invalidationOptions默认{ cancelRefetch: false }不取消进行中的请求直接触发重新拉取。useInvalidate还支持list、many、all、resourceAll等失效范围详见 invalidate 实现RefreshButton固定使用[detail]这是刷新单条记录语义的精准映射。测试与行为验证测试用例如何保障按钮行为仓库为刷新按钮提供了两层测试可分别验证 UI 行为与核心逻辑1. core 层useRefreshButton逻辑测试packages/core/src/hooks/button/refresh-button/index.spec.tsx 覆盖了文本与 i18n默认返回Refresh且可通过自定义i18nProvider的buttons.refresh键替换为其他语言文本点击触发失效mock 掉useInvalidate后调用onClick断言 invalidation 确实被触发加载态联动先用useOne拉取一次数据再调用onClick断言loading先变为true、请求完成后回到false且数据更新为最新值Post 1→Post 1 updated——这从测试层面完整复现了点击 → 失效 → 重新获取 → 按钮加载态的闭环。2. ui-tests 通用按钮测试packages/ui-tests/src/tests/buttons/refresh.tsx 提供了跨 UI 库复用的通用断言集MUI 侧在 index.spec.tsx 中直接绑定执行能正常渲染、带有正确的data-testidRefineButtonTestIds.RefreshButton支持children自定义文本hideText时不渲染文本传入onClick时优先调用自定义处理函数且不再触发useInvalidate见测试中when onClick is not passed, NOT invalidates的断言refresh.tsx——这意味着重写点击行为完全由开发者掌控MUI 侧还额外测试了startIcon与hideText的组合hideText为true且提供startIcon时只渲染自定义图标hideText为false时图标进入startIcon槽位、文本作为 children。从源码注释可以确认一个设计要点早期版本是在 UI 包内直接调用useInvalidate而现在统一改为使用 core 的useRefreshButton再内部调用useInvalidate因此刷新逻辑只需在 core 中测试一次各 UI 包只负责渲染与交互见 refresh.tsx 中被it.skip并注释说明的旧测试。定制与扩展Swizzle 与 MUI 属性透传使用 Refine CLI Swizzle 定制组件官方文档明确指出可以通过 Refine CLI 对该组件执行 swizzle拔出组件源码到项目内后自由修改。这是 Refine 组件体系的标准定制路径——当你需要改变按钮的结构、样式或行为但又不想脱离 Refine 的数据流时swizzle 是最直接的方式。透传 MUI Button 的全部属性RefreshButton除了自身属性外接受 Material UIButton的全部 props官方 API 参考中的 External Props 说明。从实现看MUI 按钮类型继承自RefineRefreshButtonProps见 ui-types其中组合了RefineButtonCommonPropshideText、childrenRefineButtonResourcePropsresource、accessControlRefineButtonSinglePropsrecordItemIdRefineButtonDataPropsdataProviderNameRefineButtonLinkingPropsonClick再加上 MUI 的ButtonProps与扩展的svgIconProps见 packages/mui 类型定义。因此你可以像使用普通 MUI 按钮一样传入sx、size、variant、color、disabled等属性。实现中对sx做了合并处理sx{{ minWidth: 0, ...sx }}保证hideText图标模式下的紧凑布局并特意从 rest props 中抽出startIcon以避免与默认图标重复渲染const { sx, startIcon, ...restProps } rest;完整属性速查表以下为RefreshButton的核心属性汇总依据 官方文档 API Reference 与 ui-types 类型定义属性类型默认值说明resourcestring从路由推断要刷新的资源名称或同名资源的identifierrecordItemIdBaseKey读取 URL 中:id要刷新的记录 iddataProviderNamestringdefault多数据源时指定目标 data providerhideTextbooleanfalse为true时只显示图标accessControl{ enabled?, hideIfUnauthorized? }{ enabled: true }按钮的权限控制配置onClickPointerEventHandler默认刷新逻辑自定义点击处理传入后不再触发默认失效childrenReactNodeRefreshi18n自定义按钮文本svgIconPropsSvgIconProps—自定义默认刷新图标的 SVG 属性MUI 集成扩展startIconReactNodeRefreshOutlined替换默认图标透传 MUIButton其余 MUI 属性ButtonProps—sx、variant、size、color、disabled等全部透传小结RefreshButton是 Refine MUI 集成中最能体现声明式数据流理念的组件之一你不需要手写取数据 → 重新请求的逻辑只需要把它放进headerButtons或工具栏它就会自动解析当前资源与记录、执行缓存失效、展示加载态并完全兼容 MUI 的样式体系。理解它的实现core 层useRefreshButtonuseInvalidate的查询 key 机制后你也能举一反三——同样的失效机制也被 Edit、Delete 等按钮用于操作完成后的数据同步。若需要更深入理解失效范围list/many/all的用法可继续阅读 useInvalidate 文档。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
