ARTICLE DETAIL

资讯详情

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

在 Refine 的 useDataGrid 中渲染关联数据:借助 useSelect 将外键列转换为可读标签的完整实战

在 Refine 的 useDataGrid 中渲染关联数据:借助 useSelect 将外键列转换为可读标签的完整实战 在 Refine 的 useDataGrid 中渲染关联数据借助 useSelect 将外键列转换为可读标签的完整实战【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读在 Refine 的 MUI 集成中useDataGrid为mui/x-data-grid的DataGrid组件提供了开箱即用的排序、过滤与分页能力但当表格列中存储的是外键如category.id时直接渲染只会显示一串 ID可读性很差。本文以官方文档 FAQ「How can I handle relational data?」中的实时示例关联数据 Live Preview 代码块为主体完整讲解如何用refinedev/core的useSelect拉取关联资源、结合singleSelect列类型与renderCell把外键列渲染成分类名称并延伸阅读useDataGrid的源码实现原理帮助你在实际项目中快速落地「外键列显示可读标签」这一高频需求。问题场景外键列直接展示 ID 的困境在典型的博客后台「文章列表」页面中posts资源里的每条记录都带有category.id外键。如果直接把该字段作为DataGrid的一列用户看到的是1、2、3这类无意义的数字无法快速理解文章归属表格也丧失了「按分类筛选」「按分类展示」的能力。正确做法是先通过useSelect一次性拉取categories资源的全部选项再把「ID → 名称」的映射交给valueOptions与renderCell使用。这正是原文档index.md 的 FAQ 章节推荐的方案。完整可运行示例以下代码完整继承自仓库中的关联数据 Live Preview 片段_partial-use-data-grid-relational-live-preview.md它同时演示了useDataGrid的分页、排序、过滤初始值与syncWithLocation以及useSelect的关系数据加载import React from react; import { useSelect } from refinedev/core; import { useDataGrid, List } from refinedev/mui; import { DataGrid, GridColDef } from mui/x-data-grid; import { ICategory, IPost } from interfaces; const PostsList: React.FC () { const { dataGridProps } useDataGridIPost({ pagination: { currentPage: 2, pageSize: 10, }, sorters: { initial: [ { field: title, order: asc, }, ], }, filters: { initial: [ { field: status, operator: eq, value: draft, }, ], }, syncWithLocation: true, }); // 1. 拉取 categories 的全部选项关闭分页 const { options, query: { isLoading }, } useSelectICategory({ resource: categories, pagination: { mode: off, }, }); const columns React.useMemoGridColDefIPost[]( () [ { field: id, headerName: ID, type: number, width: 50, }, { field: title, headerName: Title, minWidth: 400, flex: 1 }, // 2. 外键列singleSelect valueOptions renderCell { field: category.id, headerName: Category, type: singleSelect, headerAlign: left, align: left, minWidth: 250, flex: 0.5, valueOptions: options, display: flex, renderCell: function render({ row }) { if (isLoading) { return Loading...; } const category options.find( (item) item.value.toString() row.category.id.toString(), ); return category?.label; }, }, { field: status, headerName: Status, minWidth: 120, flex: 0.3, type: singleSelect, valueOptions: [draft, published, rejected], }, ], [options, isLoading], ); return ( List DataGrid {...dataGridProps} columns{columns} rowsPerPageOptions{[10, 20, 30, 50, 100]} / /List ); };提示仓库中该 Live Preview 片段被 index.md 以import RelationalPreview from ./_partial-use-data-grid-relational-live-preview.md的方式嵌入 FAQ 章节可直接在文档站点中交互预览。逐步拆解useDataGrid 的表格状态配置示例前四段配置展示了useDataGrid对DataGrid状态管理的核心能力这些参数在 index.md 的 Properties 章节有完整说明配置项示例值作用pagination.currentPage2初始页码默认1pagination.pageSize10每页条数默认25sorters.initial[{ field: title, order: asc }]初始排序规则用户改动后会被清除filters.initial[{ field: status, operator: eq, value: draft }]初始过滤条件用户改动后会被清除syncWithLocationtrue将分页/排序/过滤状态编码进 URL 查询参数可分享或收藏其中filters.initial使用的operator: eq属于 Refine 内置过滤运算符之一配合filters.permanent永久过滤不可被用户清除与filters.defaultBehaviormerge合并或replace替换默认merge可以覆盖绝大多数过滤场景。关键参数速查pagination.modeoff不分页全量拉取、client全量拉取后客户端分页、server默认按currentPage/pageSize请求sorters.mode/filters.modeserver默认参数发给服务端或off不发送交给DataGrid客户端处理sorters.permanent/filters.permanent不可被用户更改的「永久」值queryOptions透传给底层useList的 react-query 选项例如{ retry: 3 }。核心技巧用 useSelect 构建「ID → 标签」映射关系数据的核心在于下面这段高亮代码const { options, query: { isLoading }, } useSelectICategory({ resource: categories, pagination: { mode: off, }, });要点有三resource: categories指明要加载的关联资源useSelect内部通过 data provider 的getList方法拉取数据pagination.mode: off关闭分页一次性取回全部分类确保下拉选项与valueOptions完整无缺返回结构options是{ label, value }数组label为记录标题字段value为idquery对象上挂载了 react-query 的查询结果其中的isLoading用于加载态渲染。在列定义中这一映射被两处使用valueOptions: options让singleSelect列具备候选值DataGrid的过滤下拉因此能直接按分类名称筛选renderCell遍历options把当前行的row.category.id匹配到对应的label并渲染出来匹配不到时如选项尚未加载完返回undefined因此配合isLoading先渲染Loading...更稳妥。值得注意的是renderCell内部使用了options.find(...)线性查找。当分类数量很大时可以预先构建Map映射来优化分类数量适中时该写法完全够用。同时columns的useMemo依赖数组是[options, isLoading]——只有选项数据变化时才重建列定义避免每次渲染都重建导致DataGrid性能下降。深入源码useDataGrid 是如何与 useSelect 协作的从源码结构看useDataGrid的实现 展示了它与useSelect天然协作的底层设计基于useTable扩展useDataGrid内部调用refinedev/core的useTable见 index.ts#L181因此它天然继承了useTable的全部分页、排序、过滤能力而useSelect与useTable同属refinedev/core数据 hooksuseSelect 实现二者都通过 data provider 的getList取数只是返回形态不同——一个产出dataGridProps一个产出options。双向状态转换useDataGrid通过transformCrudFiltersToFilterModel/transformFilterModelToCrudFilters、transformCrudSortingToSortModel/transformSortModelToCrudSorting定义于definitions在 Refine 的CrudFilters/CrudSorting与 MUI 的GridFilterModel/GridSortModel之间做自动转换这也是onSortModelChange、onFilterModelChange能直接桥接DataGrid事件的原因。服务端过滤防抖源码在服务端过滤模式下用DEFAULT_FILTER_DEBOUNCE_MS 300index.ts#L128做输入防抖并设置filterDebounceMs: 0关闭DataGrid自身的防抖避免重复触发请求同时applyFilters会把过滤后页码重置为1index.ts#L250-L255。客户端模式切换sortingMode/filterMode会根据filtersFromProp?.mode与sortersFromProp?.mode自动判定为server或clientpaginationMode在分页关闭时返回client把分页逻辑完全交给 MUI。因此当你在表格里看到「Category 列既能显示名称、又能作为singleSelect过滤选项」时本质上是useSelect提供options→valueOptions交给DataGrid过滤引擎 →renderCell负责展示层翻译三者各司其职。实战扩展不止于分类名称掌握了「useSelectsingleSelectrenderCell」的组合拳后可以轻松推广到更多关系数据场景渲染关联资源的图片renderCell里直接返回img src{...} /或使用 MUI 的Avatar即可把用户头像、商品缩略图渲染进表格多级关系文章 → 分类 → 分类所属分组可连续调用两个useSelect在renderCell中做嵌套find按关联字段做客户端过滤配合filters.mode: off与DataGrid的过滤功能index.md FAQsingleSelect列的valueOptions会直接生成可点击的过滤候选无需服务端配合本地化标签把useSelect的结果先映射为多语言label再交给valueOptions即可让过滤下拉与单元格展示同时国际化。相关资源关联数据示例本体_partial-use-data-grid-relational-live-preview.md基础用法示例_partial-use-data-grid-basic-usage-live-preview.mduseDataGrid完整 API 文档use-data-grid/index.mduseDataGrid源码实现packages/mui/src/hooks/useDataGrid/index.tsuseDataGrid单元测试packages/mui/src/hooks/useDataGrid/index.spec.tsuseSelect源码packages/core/src/hooks/useSelect/index.ts可运行示例项目examples/table-material-ui-use-data-grid对应 CodeSandbox 示例table-material-ui-use-data-grid【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表