Refine 与 Ant Design 的 Inferencer 组件:基于数据自动生成 List/Show/Create/Edit 视图的完整指南
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
Inferencer 是 refine 生态中一个极具生产力的实验性组件包:它通过读取资源(resource)的真实 API 响应,自动推断字段类型并即时生成可复制的 List、Show、Create、Edit 四个视图组件代码。本篇指南以 v3 文档中 Ant Design 的 Inferencer 组件文档 为主体,结合当前仓库packages/inferencer的源码实现,讲解如何安装、配置、使用AntdInferencer系列组件,并深入剖析其数据获取、字段推断、关系判定与代码生成原理,帮助你在开发环境下用几行代码快速产出标准 CRUD 页面,再将生成的代码落地到真实项目。
Inferencer 是什么
@pankod/refine-inferencer(当前仓库已更名为@refinedev/inferencer,见 packages/inferencer/package.json)是一个能够根据数据结构自动为资源生成视图的包。它的目标是通过自动生成易于定制的代码,减少为每个资源手写视图所花费的时间。该包在 UI 包作用域内导出了List、Show、Create、Edit四种视图的组件。例如,@pankod/refine-inferencer/antd导出的是针对@pankod/refine-antd的组件。
对于 Ant Design 场景,Inferencer 导出以下组件:
| 组件 | 作用 |
|---|---|
AntdListInferencer | 自动生成列表视图 |
AntdShowInferencer | 自动生成详情视图 |
AntdEditInferencer | 自动生成编辑视图 |
AntdCreateInferencer | 自动生成创建视图 |
AntdInferencer | 组合组件,根据当前路由 action 自动切换到上述四个视图之一 |
从源码看,AntdInferencer是一个根据actionprop 或当前路由解析结果进行分发的组合组件。其实现位于 packages/inferencer/src/inferencers/antd/index.tsx,核心逻辑如下:
const AntdInferencer: React.FC<InferencerComponentProps> = ({ action: actionFromProps, id: idFromProps, ...props }) => { const { action, id } = useParsed(); switch (actionFromProps ?? action) { case "show": return <ShowInferencer {...props} id={idFromProps ?? id} />; case "create": return <CreateInferencer {...props} id={idFromProps ?? id} />; case "edit": return <EditInferencer {...props} id={idFromProps ?? id} />; default: return <ListInferencer {...props} id={idFromProps ?? id} />; } };也就是说,不传action时,它会读取 refine 路由器解析出的当前路由 action(如/samples/show/123对应show)自动选择视图;同时它还向外导出AntdListRenderer、AntdShowRenderer、AntdEditRenderer、AntdCreateRenderer四个 renderer 函数,供高级用户直接复用代码生成逻辑。
安装
在 v3 时代使用该包,通过包管理器安装@pankod/refine-inferencer即可。包内按 UI 库拆分了多个子路径,Ant Design 相关的组件从@pankod/refine-inferencer/antd导入:
npm install @pankod/refine-inferencer # 或 yarn add @pankod/refine-inferencer # 或 pnpm add @pankod/refine-inferencer需要说明的是,当前仓库中的包已演进为@refinedev/inferencer,其package.json(packages/inferencer/package.json)中的exports同样提供了./antd、./mui、./mantine、./chakra-ui、./headless等子路径,并已适配@refinedev/antd等新命名空间。因此在实际使用中,请以你安装的包版本对应的导入路径为准。
基本用法
Ant Design 的 Inferencer 组件可以直接在Refine组件的resourcesprop 中使用,也可以在自定义组件中通过传resourceprop(资源名)来使用。
方式一:直接在 resources prop 中使用
这是最省事的方式:把AntdInferencer同时挂到list、show、create、edit四个属性上,资源的所有 CRUD 页面即刻可用:
import { AntdInferencer } from "@pankod/refine-inferencer/antd"; const App = () => { return ( <Refine resources={[ { name: "samples", list: AntdInferencer, show: AntdInferencer, create: AntdInferencer, edit: AntdInferencer, }, ]} /> ); };此时 Inferencer 会根据当前路由自动推断 action:访问/samples渲染列表、访问/samples/show/123渲染详情,无需你手动区分。
方式二:在自定义组件中使用
如果希望把 Inferencer 嵌套在自定义布局或路由中,可以显式传入resource与action(show/edit场景还需传入id):
import { AntdInferencer } from "@pankod/refine-inferencer/antd"; const SampleList = () => { return <AntdInferencer resource="samples" action="list" />; }; const SampleShow = () => { return <AntdInferencer resource="samples" action="show" id="1" />; }; const SampleCreate = () => { return <AntdInferencer resource="samples" action="create" />; }; const SampleEdit = () => { return <AntdInferencer resource="samples" action="edit" id="1" />; };从 packages/inferencer/src/types/index.ts 的类型定义看,InferencerComponentProps还支持name(与resource二选一)、fieldTransformer、meta、hideCodeViewerInProduction等属性,后文会逐一展开。
四种视图详解
Inferencer 会为每种 action 生成不同的视图,每种视图底层组合的 refine 钩子与 Ant Design 组件也各不相同。下面结合文档与源码逐一说明。
List:列表视图
List 视图根据 API 响应生成示例列表页。文档说明它使用@pankod/refine-antd的List、Table组件以及useTable钩子。源码 packages/inferencer/src/inferencers/antd/list.tsx 中的 renderer 证实了这一点:
- 生成
const { tableProps } = useTable({ syncWithLocation: true, ... }),并通过syncWithLocation: true让表格分页、筛选状态与 URL 同步; - 根据推断结果按字段类型渲染
<Table.Column>:文本/数字用basicFields,富文本用MarkdownField(截断前 80 个字符),邮箱用EmailField,图片用ImageField(限制maxWidth: "100px"),日期用DateField,布尔值用BooleanField,URL 用UrlField,数组值用TagField逐个展示; - 依据资源的
edit、show、meta.canDelete等配置,自动追加EditButton、ShowButton、DeleteButton组成的操作列(Actions 列),删除按钮还会为useTable传入canDelete相关的查询选项。
一个完整的可运行示例(对应文档的 live 示例)如下:
import { Refine } from "@pankod/refine-core"; import { Layout } from "@pankod/refine-antd"; import routerProvider from "@pankod/refine-react-router-v6"; import dataProvider from "@pankod/refine-simple-rest"; import { AntdInferencer } from "@pankod/refine-inferencer/antd"; const API_URL = "https://api.fake-rest.refine.dev"; const App: React.FC = () => { return ( <Refine routerProvider={routerProvider} dataProvider={dataProvider(API_URL)} Layout={Layout} resources={[ { name: "samples", list: AntdInferencer, show: AntdInferencer, create: AntdInferencer, edit: AntdInferencer, canDelete: true, }, { name: "categories", list: AntdInferencer, show: AntdInferencer, }, { name: "tags", list: AntdInferencer, show: AntdInferencer, }, ]} /> ); };Show:详情视图
Show 视图根据 API 响应生成示例详情页。文档说明它使用@pankod/refine-antd的Show与 field 组件,配合@pankod/refine-core的useShow钩子。源码 packages/inferencer/src/inferencers/antd/show.tsx 中,renderer 生成const { queryResult } = useShow({ meta: ... })并从queryResult?.data?.data取出record,随后用Typography与各类 Field 组件排版字段。对于关系字段,若为多值则使用useMany拉取关联数据,单值则使用useOne,并配合queryOptions.enabled避免在数据未就绪时发起无效请求。
Create:创建视图
Create 视图根据列表 API 响应中的第一条记录生成示例创建页。文档说明它使用@pankod/refine-antd的Create组件与useForm钩子。源码 packages/inferencer/src/inferencers/antd/create.tsx 会生成:
const { formProps, saveButtonProps } = useForm({ meta: ... });- 按推断出的字段类型渲染
Form.Item:文本用Input,数字用InputNumber,布尔用Checkbox,日期用DatePicker,富文本用 Markdown 相关输入,图片用Upload(配合getValueFromEvent处理上传事件); - 对关系字段,自动生成
const { selectProps } = useSelect({ resource: "...", optionLabel: "..." })并把selectProps传给Select,实现下拉选择关联记录。
Edit:编辑视图
Edit 视图根据 API 响应生成示例编辑页。文档说明它同样使用@pankod/refine-antd的Edit组件与useForm钩子,与 Create 相比额外传入id以回填记录数据。其字段渲染逻辑与 Create 一致,同时保留saveButtonProps用于提交更新。
工作原理:Inferencer 如何自动生成视图
数据从何而来
@pankod/refine-inferencer通过<Refine/>组件配置的dataProvider获取资源数据,进而推断视图与代码。核心数据获取逻辑位于 packages/inferencer/src/use-infer-fetch/index.tsx:
- 对于
edit和showaction,发送带resource和id的单条查询(getOne); - 对于
list和createaction,发送列表查询(getList),并取响应中的第一条记录用于生成视图。
请求会携带meta(如 GraphQL 场景下的gqlQuery/gqlMutation),并在无数据或请求失败时展示错误组件。列表/创建场景下,如果对多条记录推断,代码还会统计每个字段出现频率最高的类型,构造一条"最具代表性"的记录用于渲染(见 packages/inferencer/src/create-inferencer/index.tsx 的inferMultipleRecords)。
字段类型如何被推断
推断字段类型时,Inferencer 使用一组函数,每个函数检查字段是否匹配某种特定类型并返回推断结果,同时可能返回priority(优先级)字段。例如created_at同时可被推断为date与text,此时优先级决定最终类型——优先级越高,类型越准确。默认推断器集合定义在 packages/inferencer/src/field-inferencers/index.ts:
arrayInfer, booleanInfer, dateInfer, emailInfer, imageInfer, nullishInfer, numberInfer, objectInfer, relationInfer, richtextInfer, textInfer, urlInfer以dateInfer(packages/inferencer/src/field-inferencers/date.ts)为例:当字段名以_at、_on(及其 PascalCase、UPPER_CASE 变体)结尾且值可通过 dayjs 校验,或值本身是合法的日期字符串且包含/、:、-、.分隔符时,即被推断为date类型并赋予priority: 1。
支持的全部字段类型如下:
"relation" | "array" | "object" | "date" | "email" | "image" | "url" | "richtext" | "text" | "number" | "boolean" | "unknown" | "custom_{string}"其中:
- 多值属性被识别为
array类型,并对其内部值重复同样的推断流程;object类型同理。两者都可能返回accessor字段,用于在生成视图与代码时访问属性值; - 若属性是
object类型,Inferencer 会尝试挑选一个键来代表该属性(如{ label: string; id: string; }的category会选择label)。这类带代表键的 object 字段,返回值中fieldable为true; - 可用于代表 object 类型属性的键包括:
"name" | "label" | "title" | "count" | "content" | "username" | "nickname" | "login" | "firstName" | "lastName" | "url"; custom_${string}由 UI 包自身的 Inferencer 组件在需要自定义表现时使用,当前版本用户暂时无法向组件传入自定义类型与推断函数。
relationInfer(packages/inferencer/src/field-inferencers/relation.ts)的实现揭示了关系判定的正则基础:
export const relationRegexp = /(-id|-ids|_id|_ids|Id|Ids|ID|IDs)(\[\])?$/;即字段名以-id、_id、Id、ID、Ids等结尾(camelCase、PascalCase、snake_case、kebab-case、UPPER_CASE、lower_case 均支持,且可带[]数组括号),且值为字符串/数字或字符串/数字数组时,即标记为relation类型,多值场景multiple为true。
关系资源如何确定
在判定字段是否为关系后,Inferencer 会尝试确定关联资源。判定过程不会主动触发额外的 API 调用,满足以下任一条件即视为关系候选:
- 属性名以
id或ids结尾(支持各种命名风格及[]); - 属性是仅含单一
id属性的对象; - 属性是仅含单一
id属性(或 UUID 兼容字符串/数字)的对象数组; - 属性是字符串或数字,且属性名与已知资源(单数或复数)匹配。
确定关联资源时按以下顺序进行:
- 优先尝试在
resources数组中查找与属性名(单数或复数)匹配的资源; - 找到匹配资源则直接使用它作为关联资源;
- 未找到时,向
defaultdataProvider分别发送单数、复数属性名(去除id后缀)的两次请求; - 若请求成功(HTTP 200),则认为属性是
relation类型并把该资源设为关联资源,后续使用该资源及其dataProvider(若指定)以属性值发起关联查询; - 若请求均失败,则移除属性的
relation标记,按普通字段处理;若为object类型,则尝试挑选最合适的代表属性。
如果dataProvider与resources的工作方式特殊,导致 Inferencer 无法找到关系资源,可以通过fieldTransformer函数手动修改推断字段(详见下文)。
组件如何渲染、代码如何生成
字段确定后,Inferencer 使用renderer函数生成组件代码,同时用同一份代码在页面中实时渲染视图(组件渲染依赖 react-live 的 TypeScript 支持分支实现,见文档说明)。renderer按 action 类型与 UI 包分别构建——也就是说@pankod/refine-inferencer/antd与其他 UI 作用域的list、show、edit、create各有独立的 renderer 函数。
renderer返回一段包含组件代码的字符串,这段代码会展示给用户复制粘贴到自己的项目里;同样的代码也被用于在视图中实时渲染组件。组件名称由当前resource元素与当前 action 决定:若资源有option.label字段则作为组件名的一部分,否则使用resource.name。例如资源名categories与 actionlist组合,生成CategoryList组件。整体编排逻辑集中在工厂函数createInferencer(packages/inferencer/src/create-inferencer/index.tsx)中:它组合默认推断器与自定义推断器、默认转换器与自定义转换器,通过useInferFetch获取数据、useRelationFetch解析关系,最后把生成代码交给LiveComponent渲染,并在下方展示SharedCodeViewer代码查看器。
自定义输出:修改推断字段(fieldTransformer)
如果你希望定制 Inferencer 的输出——例如为object类型字段设置自定义accessor、改变某个字段的type,或修改relation类型字段的关联resource——可以在 Inferencer 组件上使用fieldTransformerprop。它是一个接收字段并返回修改后字段的函数;若返回undefined | false | null,则该字段会从输出(包括预览与代码)中移除。
结合类型定义(packages/inferencer/src/types/index.ts)与createInferencer的实现,fieldTransformer在默认的fieldTransformers之后执行,可用来:
<AntdInferencer resource="samples" action="create" fieldTransformer={(field) => { // 隐藏不需要的字段 if (field.key === "internalNote") { return undefined; } // 修改 object 字段的代表键 if (field.key === "category" && field.type === "object") { return { ...field, accessor: "name" }; } return field; }} />此外,InferencerComponentProps还提供meta(按资源名/标识符为getList、getMany、getOne、update、create等 data provider 方法传参,支持 GraphQL 的gqlQuery/gqlMutation)与hideCodeViewerInProduction(生产模式下隐藏代码查看器与信息块)等高级配置。
完整示例与体验方式
文档末尾提供了一个完整可运行的 CodeSandbox 示例,对应仓库中的 examples/inferencer-antd 目录。该示例工程内置了完整的<Refine>配置:以@pankod/refine-simple-rest对接https://api.fake-rest.refine.dev,使用 react-router v6 路由,并为samples、categories、tags等多个资源挂载AntdInferencer。你可以直接在仓库中查看其 package.json 与页面源码,或在本地安装依赖后启动开发服务器,观察 Inferencer 实时生成视图并复制生成代码的效果。
使用注意事项
- 实验性包:
@pankod/refine-inferencer是实验性包,目前仍处于早期开发阶段,官方团队正在持续改进并添加新特性; - 仅限开发环境:Inferencer 组件面向开发环境使用,不应在生产环境使用。最佳实践是在开发阶段用 Inferencer 快速生成页面骨架,再将生成的代码复制进项目进行定制;
- 数据驱动:生成效果完全取决于 dataProvider 返回的数据结构与资源配置,数据越规整、关系越明确,生成的视图越准确;
- 版本差异:v3 文档使用
@pankod/refine-inferencer与@pankod/refine-antd命名空间,而当前仓库中的包已演进为@refinedev/inferencer(见 packages/inferencer/package.json),Ant Design 组件源码也已适配@refinedev/antd,导入路径请与所安装版本保持一致。
总结
AntdInferencer及其四个分视图组件把"根据 API 响应自动推断并生成 CRUD 页面代码"这一能力完整封装进了 refine 的资源体系:挂在resources上即可随路由自动渲染,传入resource/action/id即可嵌入自定义页面;背后则是字段类型推断器、关系资源探测、renderer 代码生成与 react-live 实时渲染的完整流水线。掌握它之后,你可以先让 Inferencer 在开发环境"铺出"一套标准 Ant Design 后台页面,再通过fieldTransformer微调输出、复制代码深度定制,从而把宝贵时间从重复的表单与表格样板代码中解放出来。
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考