ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

refine 框架 Chakra UI 的 `<EditButton>` 编辑按钮:用法、属性与源码级实现解析

refine 框架 Chakra UI 的 `<EditButton>` 编辑按钮:用法、属性与源码级实现解析 refine 框架 Chakra UI 的EditButton编辑按钮用法、属性与源码级实现解析【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineEditButton是 refine 为 Chakra UI 提供的内置编辑按钮组件用于在列表页中一键跳转到资源的编辑页面并在后台自动携带当前记录的 id 构造路由。本文基于 refine 仓库中 Edit 按钮文档refine v3.xx.xx 文档体系展开并结合 组件实现、核心按钮 Hook 与 通用按钮测试 等源码带你掌握它的全部属性、真实跳转逻辑与权限控制行为从而在列表、表格等场景中正确使用它。一、组件概览一个按钮如何完成跳转到编辑页这件事EditButton底层渲染的是 Chakra UI 的Button组件内部通过useNavigation的edit方法完成页面跳转。它最常见的用途是在资源resource的列表页或表格的操作列中为每一行渲染一个编辑入口点击后带着该行记录的 id 跳转到/resource/edit/:id。从 源码 可以看到EditButton是一个接收EditButtonProps的函数组件内部调用了来自refinedev/core的useEditButtonHookexport const EditButton: React.FCEditButtonProps ({ resource: resourceNameFromProps, recordItemId, hideText false, accessControl, svgIconProps, meta, children, onClick, ...rest }) { const { to, label, title, hidden, disabled, LinkComponent } useEditButton({ resource: resourceNameFromProps, id: recordItemId, accessControl, }); // ... };而 packages/core/src/hooks/button/index.tsx 中useEditButton只是useNavigationButton的一个特定action变体export const useEditButton ( props: PrettifyOmitNavigationButtonProps, action, ) useNavigationButton({ ...props, action: edit });也就是说EditButton的导航行为与ShowButton、CloneButton、ListButton等按钮完全共享同一套核心逻辑区别仅在于action的值edit/show/clone/list。组件的两种渲染形态在 index.tsx 中组件根据hideText决定渲染形态默认带文字渲染 Chakra UI 的Button variantoutline左侧通过leftIcon放置IconPencil来自tabler/icons-react按钮文本优先取children否则使用useEditButton计算出的labelhideText仅图标渲染IconButton variantoutline只显示IconPencil图标并将label作为aria-label以保证无障碍访问。两种形态都会带上统一的data-testidRefineButtonTestIds.EditButton与classNameRefineButtonClassNames.EditButton方便端到端测试与样式定制。按钮外层包裹的是useLink()返回的LinkComponent因此点击行为本质上是一次客户端路由跳转而非普通的事件回调。二、基本用法在 Chakra UI 表格中接入编辑操作2.1 最小可运行示例下面是文档给出的完整示例在pankod/refine-chakra-ui与pankod/refine-react-table组合下把EditButton放进表格的 Actions 列import { List, TableContainer, Table, Thead, Tr, Th, Tbody, Td, EditButton, } from pankod/refine-chakra-ui; import { useTable, ColumnDef, flexRender } from pankod/refine-react-table; const PostList: React.FC () { const columns React.useMemoColumnDefIPost[]( () [ { id: id, header: ID, accessorKey: id, }, { id: title, header: Title, accessorKey: title, }, { id: actions, header: Actions, accessorKey: id, cell: function render({ getValue }) { return ( EditButton recordItemId{getValue() as number} / ); }, }, ], [], ); const { getHeaderGroups, getRowModel, refineCore: { setCurrent, pageCount, current }, } useTable({ columns, }); return ( List TableContainer Table variantsimple whiteSpacepre-line Thead {getHeaderGroups().map((headerGroup) ( Tr key{headerGroup.id} {headerGroup.headers.map((header) { return ( Th key{header.id} {!header.isPlaceholder flexRender( header.column.columnDef.header, header.getContext(), )} /Th ); })} /Tr ))} /Thead Tbody {getRowModel().rows.map((row) { return ( Tr key{row.id} {row.getVisibleCells().map((cell) { return ( Td key{cell.id} {flexRender( cell.column.columnDef.cell, cell.getContext(), )} /Td ); })} /Tr ); })} /Tbody /Table /TableContainer /List ); }; interface IPost { id: number; title: string; }对应的资源注册App组件中需要同时提供list与edit页面EditButton才能正常跳转const App () { return ( Refine notificationProvider{RefineChakra.notificationProvider()} resources{[ { name: posts, list: PostList, edit: EditPage, }, ]} / ); };2.2 跳转路径是如何算出来的点击按钮后路径由 navigation-button 的实现 计算const to React.useMemo(() { if (!resource) return ; switch (props.action) { case create: case list: return navigation${props.action}Url; default: if (!id) return ; return navigation${props.action}Url; } }, [resource, id, props.meta, navigation[${props.action}Url]]);对于edit这种需要记录 id 的 action如果当前没有解析出id例如既没有通过recordItemId传入也无法从当前路由参数推断to会返回空字符串按钮点击将无效果。这解释了为什么表格场景中必须通过recordItemId{getValue()}显式传入行 id。useResourceParams会在没有显式传入id时尝试从当前路由的 URL 参数中推断记录 idresource则优先使用 props 传入的resource否则取当前资源上下文。按钮文案label通过translate(buttons.edit, humanize(edit))生成默认即Edit。三、属性详解文档中的属性全部继承自RefineEditButtonProps见 packages/chakra-ui/src/components/buttons/types.ts其中去掉了ignoreAccessControlProvider并额外支持svgIconProps用于透传给 Tabler 图标的属性。3.1recordItemId用于把记录 id 追加到路由路径的末尾构造出/resource/edit/:id形式的跳转目标。当按钮处于列表/表格的 Actions 列时需要把当前行的 id 传给它import { EditButton } from pankod/refine-chakra-ui; const MyEditComponent () { return EditButton colorSchemeblack recordItemId123 /; };如果不传recordItemId组件会尝试从当前路由参数推断 id在详情页等场景下可行在列表页则必须显式传入否则无法生成跳转路径。3.2resourceNameOrRouteName用于指定重定向的资源路由端点跳转目标为resourceNameOrRouteName/edit。默认情况下EditButton使用当前资源对象的name属性作为端点。import { EditButton } from pankod/refine-chakra-ui; const MyEditComponent () { return ( EditButton colorSchemeblack resourceNameOrRouteNamecategories recordItemId2 / ); };点击该按钮会触发useNavigation的edit方法把应用重定向到/categories/edit/2。注意当前组件处于posts资源页面中而跳转目标是categories因此需要在resources中同时注册categories的edit页面const App () { return ( Refine resources{[ { name: posts, list: MyEditComponent, }, { name: categories, edit: EditPage, }, ]} / ); };3.3hideText控制是否显示按钮文字。为true时只显示铅笔图标import { EditButton } from pankod/refine-chakra-ui; const MyEditComponent () { return EditButton colorSchemeblack recordItemId123 hideText /; };从前文源码可知hideText会让组件渲染IconButton并把label放入aria-label在压缩表格列宽或追求紧凑 UI 时非常实用。在 通用按钮测试 中也有对应用例hideText渲染后页面中不应再出现 Edit 文本。3.4accessControl用于配合accessControlProvider控制按钮的可见性与可用性enabled: boolean是否对该按钮执行访问控制检查hideIfUnauthorized: boolean当用户无权限时是否直接隐藏按钮。只有在给Refine/提供了accessControlProvider时该属性才生效。示例import { EditButton } from pankod/refine-chakra-ui; export const MyListComponent () { return ( EditButton accessControl{{ enabled: true, hideIfUnauthorized: true }} / ); };从 navigation-button 源码 可以看到权限判断由useButtonCanAccess完成它会基于action、id、resource调用can方法并返回canAccess、title、hidden、disabled四个值无权限且未隐藏时按钮进入disabled状态title显示can返回的拒绝原因如 Access Denied无权限且hideIfUnauthorized为true时hidden为真组件会直接返回null按钮完全不渲染。组件中还做了disabled disabled || rest.disabled、hidden hidden || rest.hidden的合并因此手动传入的disabled/hidden与权限系统得出的结果取并集测试用例 专门验证了即使有权限手动disabled依然生效的行为。3.5 其余常用属性resource与resourceNameOrRouteName等价的新版命名在组件 props 中通过resource: resourceNameFromProps解构后传入useEditButtonmeta透传给useNavigation的editUrl生成逻辑的元数据如自定义路由参数用于生成带额外查询信息的路由children自定义按钮文本优先级高于自动生成的labelchildren ?? labelonClick点击回调。从 实现 看传入onClick时会先preventDefault()阻止默认跳转再调用回调因此该属性适合点击后做额外处理但不跳转的场景svgIconProps透传给铅笔图标的 Tabler 图标属性如size、stroke等其余...rest透传给 Chakra UI 的Button/IconButton因此 Chakra UI Button 的全部 propscolorScheme、variant、size、isLoading等都可用。四、源码视角按钮背后还有哪些保障4.1 跨 UI 库的统一测试契约所有 UI 集成包的EditButton都必须通过refinedev/ui-tests的buttonEditTests测试套件。Chakra UI 的实现 只有寥寥数行import { buttonEditTests } from refinedev/ui-tests; import { EditButton } from ./; describe(Edit Button, () { buttonEditTests.bind(this)(EditButton); });而 通用测试主体 覆盖了默认渲染可用、disabled生效且阻断点击、hidden不渲染、data-testid存在、children文本渲染、hideText仅图标、以及一整套 access control 组合全局开启/关闭、prop 覆盖、hideIfUnauthorized优先级等。这意味着无论你使用 Chakra UI、Ant Design 还是 MUIEditButton的行为语义都是一致的。4.2 跳转目标可被测试验证测试用例 用 React Router 模拟路由并断言最终hrefRoute path/:resource element{EditButton resourcecategories recordItemId1 /} / // 点击后断言 expect(editLink?.getAttribute(href)).toBe(/categories/edit/1);它验证了resource与recordItemId组合后生成的跳转地址正是/categories/edit/1与文档描述的触发useNavigation的edit方法并跳转到resourceNameOrRouteName/edit/:id完全一致。五、常见问题与注意事项列表页中必须传recordItemId从 路径计算逻辑 可知editaction 缺少id时to为空字符串按钮点击无效。表格/列表场景请务必从当前行取值传入。跨资源跳转记得注册目标资源的edit页面使用resourceNameOrRouteName或resource指向其他资源时resources中必须存在对应的edit路由否则会 404。权限控制与手动禁用是叠加关系disabled/hidden是手动值 OR 权限结果即使权限通过显式传入的disabled依然会让按钮不可点击。onClick会阻止默认跳转如果你只是想在跳转前做日志或确认请自行在回调内调用useNavigation().edit(...)完成导航或在回调后手动触发路由跳转。自定义文本优先children的优先级高于自动 label国际化场景也可以直接传翻译后的文案或者通过 i18n 的buttons.edit键值统一覆盖。六、小结EditButton是一个极薄的适配层UI 部分由 Chakra UI 的Button/IconButton提供路由与权限逻辑则全部收敛到refinedev/core的useNavigationButtonaction: edit中。通过recordItemId携带记录 id、通过resourceNameOrRouteName/resource指定跳转资源、通过accessControl接入权限系统你可以在不手写任何路由代码的情况下为列表页快速补齐编辑入口。想进一步深挖底层实现可以直接阅读 Chakra UI 按钮实现、核心导航按钮 Hook 以及 通用按钮测试契约。如果想要完全自定义该组件的样式与行为还可以通过 refine CLI 的swizzle命令将其弹出swizzle到你的项目中在本地副本上任意修改相关说明见 refine CLI 文档。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表