
Refine 教程深入理解 Ant DesignList组件——列表页布局、属性详解与源码级解析【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读List是 Refine 中构建列表页List View的基础布局组件。本文将以 documentation/versioned_docs/version-3.xx.xx/api-reference/antd/components/basic-views/list.md 为骨架完整讲解List的定位、全部核心属性title、resource、canCreate、breadcrumb、wrapperProps等与实战用法并深入到pankod/refine-antd的源码实现剖析其内部渲染结构与默认行为。读完本文你将掌握如何在 Refine 中快速搭建可复用、可高度定制的列表页理解创建按钮、面包屑、标题等功能的默认逻辑与全局配置方式。List是什么纯布局组件不含业务逻辑List是一个纯粹的页面布局组件它自身不包含任何业务逻辑只负责提供列表页的外层结构并附带创建按钮页面标题等增强功能。你可以把它理解为一个页面容器在容器内部自由摆放表格、卡片、自定义内容。从源码可以更清晰地看到这一点。在 packages/antd/src/components/crud/list/index.tsx 中List的渲染结构是div {...wrapperProps} // 最外层包装 PageHeader title{...} // 标题 extra{...} // 头部按钮区创建按钮等 breadcrumb{...} // 面包屑 {...headerProps} // 头部透传属性 div {...contentProps}{children}/div // 内容区 /PageHeader /div也就是说List的 DOM 结构由外层divPageHeader头部 内容div三部分组成所有传入的children都会被放入内容区。也正因为不含逻辑你可以把List用在任何资源页面上包括自定义页面。一个完整的列表页示例下面的示例来自关联文档展示了一个结合useTable与useMany的典型posts列表页表格展示文章 ID、标题、分类名称与状态其中分类名通过useMany从categories资源按 ID 批量查询得到interface ICategory { id: number; title: string; } interface IPost { id: number; title: string; content: string; status: published | draft | rejected; category: { id: number }; } // visible-block-start import { useMany } from pankod/refine-core; import { List, Table, TextField, TagField, useTable, } from pankod/refine-antd; const PostList: React.FC () { const { tableProps } useTableIPost({ syncWithLocation: true, }); const categoryIds tableProps?.dataSource?.map((item) item.category.id) ?? []; const { data, isLoading } useManyICategory({ resource: categories, ids: categoryIds, queryOptions: { enabled: categoryIds.length 0, }, }); return ( List Table {...tableProps} rowKeyid Table.Column dataIndexid titleID / Table.Column dataIndextitle titleTitle / Table.Column dataIndex{[category, id]} titleCategory render{(value) { if (isLoading) { return TextField valueLoading... /; } return ( TextField value{data?.data.find((item) item.id value)?.title} / ); }} / Table.Column dataIndexstatus titleStatus render{(value: string) TagField value{value} /} / /Table /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );要点解读List包裹Table自动获得页头、标题、创建按钮等布局能力useTable负责数据获取与表格 props分页、排序、筛选useMany批量加载分类数据用queryOptions.enabled避免无 ID 时的无效请求。Swizzle用 refine CLI 自定义组件如果默认布局不满足需求可以通过 Swizzle 机制把List源码弹出到你的项目中自由修改。使用refine CLI即可npm run refine swizzle在交互式界面中选择List组件后其源码会被复制到项目src目录下之后你对该副本的所有修改不再受 Refine 包版本升级影响这是 Refine 官方推荐的深度定制方式。属性详解List的全部配置项title自定义页面标题title用于设置List的标题。不传时默认使用资源名的复数形式例如posts资源显示为 Posts。从源码看标题的解析逻辑位于 packages/antd/src/components/crud/list/index.tsxtitle{ title ?? translate( ${identifier}.titles.list, getUserFriendlyName(resource?.meta?.label ?? identifier, plural), ) }也就是说标题优先级为显式传入的title i18n 翻译键{resource}.titles.list 资源名的复数形式可配合meta.label自定义。// visible-block-start import { List } from pankod/refine-antd; const PostList: React.FC () { return ( /* highlight-next-line */ List titleCustom Title pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );resource在自定义页面中指定资源List默认从当前路由解析资源信息即 URL 中的:resource参数。但在自定义页面非资源路由中路由里没有资源信息此时必须显式传入resourceprop 来告诉组件要操作哪个资源。完整用法参见 custom-pages.mdsetInitialRoutes([/custom]); // visible-block-start import { Refine } from pankod/refine-core; import { List } from pankod/refine-antd; import routerProvider from pankod/refine-react-router-v6; import dataProvider from pankod/refine-simple-rest; const CustomPage: React.FC () { return ( /* highlight-next-line */ List resourceposts pRest of your page here/p /List ); }; const App: React.FC () { return ( Refine routerProvider{{ ...routerProvider, // highlight-start routes: [ { element: CustomPage /, path: /custom, }, ], // highlight-end }} dataProvider{dataProvider(https://api.fake-rest.refine.dev)} resources{[{ name: posts }]} / ); }; // visible-block-end render(App /);在源码中resource通过useResourceParams({ resource: resourceFromProps })解析并同时得到identifier资源标识符用于后续标题翻译与创建按钮路由见 packages/antd/src/components/crud/list/index.tsx。canCreate与createButtonProps控制创建按钮canCreate控制是否在List头部显示创建按钮默认行为只要该资源配置了create组件Refine 就会自动添加创建按钮此时canCreate默认为true否则为false创建按钮会根据从 URL 读取的信息跳转到该资源的创建页。源码中的判定逻辑非常直接packages/antd/src/components/crud/list/index.tsxconst isCreateButtonVisible canCreate ?? (!!resource?.create || !!createButtonPropsFromProps);即优先级为显式传入的canCreate 资源是否配置了create组件 是否传入了createButtonProps。若想自定义按钮本身尺寸、文案、图标等使用createButtonProps其类型为 Ant Design 的ButtonProps并额外支持resourceName。下面的例子结合usePermissions实现了按权限控制创建按钮只有admin权限才显示且按钮尺寸为smallconst { Create } RefineAntd; const { default: simpleRest } RefineSimpleRest; const dataProvider simpleRest(https://api.fake-rest.refine.dev); const customDataProvider { ...dataProvider, create: async ({ resource, variables }) { return { data: {}, }; }, }; const authProvider { login: () Promise.resolve(), logout: () Promise.resolve(), checkAuth: () Promise.resolve(), checkError: () Promise.resolve(), getPermissions: () Promise.resolve(admin), getUserIdentity: () Promise.resolve(), }; // visible-block-start import { List } from pankod/refine-antd; import { usePermissions } from pankod/refine-core; const PostList: React.FC () { const { data: permissionsData } usePermissions(); return ( List /* highlight-start */ canCreate{permissionsData?.includes(admin)} createButtonProps{{ size: small }} /* highlight-end */ pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo authProvider{authProvider} dataProvider{customDataProvider} initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, create: () { return CreateCreate Page/Create; }, }, ]} /, );usePermissions的完整用法可参考 usePermissions.md。源码侧补充List内部会组装createButtonPropspackages/antd/src/components/crud/list/index.tsxconst createButtonProps: CreateButtonProps | undefined isCreateButtonVisible ? { size: middle, resource: identifier, ...createButtonPropsFromProps, } : undefined;默认注入size: middle与resource你自己的属性会通过展开运算符覆盖默认值。而真正渲染的CreateButton内部基于 Ant DesignButton使用useCreateButtonhook 计算跳转地址并带有PlusSquareOutlined图标与typeprimary样式它还会响应 accessControl访问控制当无权限时按钮会被禁用或隐藏。breadcrumb自定义或禁用面包屑breadcrumb用于定制页面顶部的面包屑导航。默认使用pankod/refine-antd包内的Breadcrumb组件该组件基于 Ant Design Breadcrumb 与useBreadcrumbhook 构建可根据当前路由层级自动生成首页 / 资源 / 记录导航。// visible-block-start import { List } from pankod/refine-antd; const CustomBreadcrumb: React.FC () { return ( p style{{ padding: 3px 6px, border: 2px dashed cornflowerblue, }} My Custom Breadcrumb /p ); }; const PostList: React.FC () { return ( List // highlight-start breadcrumb{CustomBreadcrumb /} // highlight-end pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );全局配置面包屑可以通过Refine组件的options.breadcrumb在全局统一管理例如全局自定义或全局禁用。从源码可以看到优先级packages/antd/src/components/crud/list/index.tsxconst breadcrumb typeof breadcrumbFromProps undefined ? globalBreadcrumb : breadcrumbFromProps;即组件级breadcrumb优先未传时回退到Refine的全局配置二者都没有时才渲染默认Breadcrumb /见 packages/antd/src/components/crud/list/index.tsx。wrapperProps定制最外层包装List的最外层是一个简单divwrapperProps可以接收div支持的任何属性className、style、事件等。例如给整个列表页加背景色与内边距// visible-block-start import { List } from pankod/refine-antd; const PostList: React.FC () { return ( List // highlight-start wrapperProps{{ style: { backgroundColor: cornflowerblue, padding: 16px, }, }} // highlight-end pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );对应源码中的div {...(wrapperProps ?? {})}packages/antd/src/components/crud/list/index.tsx。headerProps定制头部区域headerProps用于定制List的头部其类型为 Ant Design Pro 的PageHeaderProps。它可以设置subTitle副标题、style、extra等属性。示例// visible-block-start import { List } from pankod/refine-antd; const PostList: React.FC () { return ( List // highlight-start headerProps{{ subTitle: This is a subtitle, style: { backgroundColor: cornflowerblue, padding: 16px, }, }} // highlight-end pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );源码中headerProps通过展开运算符透传给PageHeaderpackages/antd/src/components/crud/list/index.tsx因此title、breadcrumb、extra等由List内部管理的属性会被你的headerProps覆盖或补充。contentProps定制内容区List的内容区同样由div包裹contentProps可接收div支持的任何属性。示例// visible-block-start import { List } from pankod/refine-antd; const PostList: React.FC () { return ( List // highlight-start contentProps{{ style: { backgroundColor: cornflowerblue, padding: 16px, }, }} // highlight-end pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );对应源码中的div {...(contentProps ?? {})}{children}/divpackages/antd/src/components/crud/list/index.tsx。headerButtons定制头部按钮headerButtons允许自定义头部操作按钮区接收两种形式React.ReactNode直接替换默认按钮渲染函数({ defaultButtons, createButtonProps }) React.ReactNode在保留默认按钮即创建按钮的基础上追加自定义按钮。// visible-block-start import { List, Button } from pankod/refine-antd; const PostList: React.FC () { return ( List // highlight-start headerButtons{({ defaultButtons }) ( {defaultButtons} Button typeprimaryCustom Button/Button / )} // highlight-end pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );源码实现packages/antd/src/components/crud/list/index.tsxextra{ headerButtons ? ( Space wrap {...headerButtonProps} {typeof headerButtons function ? headerButtons({ defaultButtons: defaultExtra, createButtonProps, }) : headerButtons} /Space ) : ( defaultExtra ) }当传入headerButtons时按钮区会被Space wrap包裹函数形式会收到defaultButtons默认创建按钮与createButtonProps两个参数方便你决定保留、改造或替换默认按钮。此类型定义在 packages/ui-types/src/types/crud.tsx 中headerButtons的类型为ActionButtonRenderer同时支持节点与渲染函数。headerButtonProps定制头部按钮的包装元素headerButtonProps用于定制包裹头部按钮的Space组件其类型为 Ant Design 的SpaceProps可控制按钮间距、换行、对齐方式等// visible-block-start import { List, Button } from pankod/refine-antd; const PostList: React.FC () { return ( List // highlight-start headerButtonProps{{ style: { backgroundColor: cornflowerblue, padding: 16px, }, }} // highlight-end headerButtons{Button typeprimaryCustom Button/Button} pRest of your page here/p /List ); }; // visible-block-end render( RefineAntdDemo initialRoutes{[/posts]} resources{[ { name: posts, list: PostList, }, ]} /, );属性总览API ReferenceList的完整属性定义基于RefineCrudListProps泛型见 packages/ui-types/src/types/crud.tsx在 Ant Design 集成中被实例化为 packages/antd/src/components/crud/types.ts 中的ListProps。汇总如下属性类型默认值说明titleReact.ReactNode资源名的复数形式或{resource}.titles.list的翻译页面标题resourcestring从 URL 的:resource读取资源名自定义页面中必须显式指定canCreateboolean资源配置了create组件时为true否则false是否显示创建按钮createButtonPropsButtonProps { resourceName: string }{ size: middle, resource: identifier }创建按钮的自定义属性breadcrumbReact.ReactNodeBreadcrumb /可被Refine的options.breadcrumb全局覆盖面包屑wrapperPropsdiv的 HTML 属性—最外层包装属性headerPropsPageHeaderProps—头部PageHeader属性contentPropsdiv的 HTML 属性—内容区包装属性headerButtonsReact.ReactNode或({ defaultButtons, createButtonProps }) React.ReactNode当canCreate时渲染CreateButton /否则为null头部按钮headerButtonPropsSpaceProps—头部按钮包装Space属性常见问题与实战建议想在自定义页面使用List务必传入resource否则标题翻译、创建按钮跳转、面包屑都将因为没有资源上下文而失效。不想显示创建按钮在资源未配置create组件时它默认不显示若资源已配置create但页面不需要显式传canCreate{false}。全局统一管理面包屑不要在每个List上重复传breadcrumb优先在Refine options{{ breadcrumb: ... }}中配置组件级传入会覆盖全局配置。深度定制组件使用 refine CLI 的 swizzle 命令将List源码弹出到项目中进行修改避免直接改 node_modules。小结List作为 Refine Ant Design 集成中列表页的骨架组件职责清晰提供页面标题、面包屑、创建按钮与布局结构把数据获取和业务逻辑交给useTable、useMany等 hooks。通过title、canCreate、breadcrumb、wrapperProps、headerButtons等属性你可以在不改动任何业务代码的前提下快速完成列表页从默认可用到完全定制的演进。其类型定义统一沉淀在 packages/ui-types/src/types/crud.tsx 中这意味着 MUI、Chakra UI、Mantine 等其他 UI 集成的List组件也遵循同一套属性契约掌握本文内容后可以无缝迁移到其他 UI 框架。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考