Refine Inferencer 指南:基于数据结构自动生成 List / Show / Create / Edit 视图与代码
2026/9/12 16:32:57 网站建设 项目流程

Refine 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

@refinedev/inferencer是 refine 生态中用于自动生成资源视图的包:它通过<Refine />组件中配置的dataProvider拉取真实数据,基于数据结构自动推断字段类型、关系(relation)与展示方式,进而生成List、Show、Create、Edit四种视图的完整代码,且生成的代码可直接复制进项目继续定制。阅读本文后,你将掌握 Inferencer 的安装方式、字段推断与关系判定原理、GraphQLmeta配置语法、fieldTransformer定制手段,以及生产环境的正确使用边界。

安装与基础用法

在 refine 项目中安装 Inferencer:

npm install @refinedev/inferencer

(使用 pnpm 或 yarn 时替换为pnpm add @refinedev/inferenceryarn add @refinedev/inferencer

该包按 UI 框架拆分导出,组件位于各 UI 包作用域内,例如@refinedev/inferencer/antd导出的是配合@refinedev/antd使用的组件。包入口在 packages/inferencer/src/index.tsx,统一导出createInferencerSharedCodeViewer及一系列供二次开发使用的工具函数与类型。以 Ant Design 为例:

import { AntdInferencer } from "@refinedev/inferencer/antd"; const App = () => { return ( <Refine /* dataProvider、resources 等配置 */ > <AntdInferencer action="list" resource="posts" /> </Refine> ); };

组件可用的核心 props 定义于 packages/inferencer/src/types/index.ts:

  • name/resource:指定要推断的资源名(二选一,未传时从当前路由解析);
  • action"list" | "show" | "edit" | "create",默认"list"
  • id:当actionshowedit时指定要推断的单条记录;
  • fieldTransformer:字段级自定义转换函数;
  • meta:按资源/方法分层传入 GraphQL 等后端所需的 meta 值;
  • hideCodeViewerInProduction:生产模式下隐藏代码查看器与提示组件。

可用的 UI Inferencer

Inferencer 为以下 UI 体系分别提供实现,各自拥有独立的 List/Show/Create/Edit 渲染器与代码模板:

  • Ant Design:@refinedev/inferencer/antd
  • Material UI:@refinedev/inferencer/mui
  • Mantine:@refinedev/inferencer/mantine
  • Chakra UI:@refinedev/inferencer/chakra-ui
  • Headless(无 UI 依赖):@refinedev/inferencer/headless

仓库中每种 UI 的实现目录结构一致,以 Ant Design 为例,位于 packages/inferencer/src/inferencers/antd,包含list.tsxshow.tsxcreate.tsxedit.tsxloading.tsxerror.tsxcode-viewer.tsx;MUI、Mantine、Chakra UI、Headless 的实现分别位于 packages/inferencer/src/inferencers/mui、packages/inferencer/src/inferencers/mantine、packages/inferencer/src/inferencers/chakra-ui、packages/inferencer/src/inferencers/headless。

工作原理

简单来说,Inferencer 通过<Refine />dataProvider拉取资源数据,依据数据结构生成视图和代码。整体流程由 packages/inferencer/src/create-inferencer/index.tsx 中的createInferencer工厂驱动:它把一组字段推断函数与字段转换函数组合起来,先取数、再逐字段推断、经转换器处理、最后交给渲染器生成代码,并用改造后的react-live将同一份代码实时渲染在页面上。

数据如何获取

  • editshow:发送带resourceid的单条记录请求(getOne),id可来自idprop 或当前路由参数;
  • listcreate:发送resource的列表请求(getList),取其中一条记录用于推断视图。

上述取数逻辑在 packages/inferencer/src/use-infer-fetch/index.tsx 的useInferFetch中实现:它依据action类型调用对应的dataProvider方法,并管理loadinginitialerror状态;当列表请求返回空数据时,会给出提示信息,指引开发者检查 dataProvider 与 resource 配置。

字段类型如何推断

推断阶段会按顺序运行一组函数,每个函数负责检查某一特定类型并返回推断结果;若多个函数都能命中同一字段,则通过返回值中的priority字段决出最终类型——优先级越高,判定越精确。例如created_at字段值是一个字符串,它既能被推断为date也能被推断为text,此时由priority决定采用更精确的date

默认的字段推断函数集合定义在 packages/inferencer/src/field-inferencers/index.ts,包含:arrayInferbooleanInferdateInferemailInferimageInfernullishInfernumberInferobjectInferrelationInferrichtextInfertextInferurlInfer

推断得到的结果结构为InferField(见 packages/inferencer/src/types/index.ts),关键字段包括:

  • key:字段名;
  • type:推断出的字段类型;
  • relation:是否为关系字段;
  • multiple:是否为多值(数组)字段;
  • fieldable:对象类型字段是否找到了可代表它的展示键;
  • accessor:从记录中取值所用的访问路径(为数组时表示多个值需拼接);
  • resource:关系字段对应的资源;
  • priority:推断优先级;
  • relationInfer:关系字段内部记录的推断结果。

多值属性被标记为array类型,同时会对数组内的值重复执行同样的推断流程;object类型属性同理,两者都可能返回accessor字段,用于生成视图与代码时取值。若属性是对象类型,则尝试挑选一个键来代表该属性,例如category: { label: string; id: string }会选择label作为代表键;这类对象字段的返回值中fieldabletrue

可用字段类型(InferType

type Types = | "relation" | "array" | "object" | "date" | "email" | "image" | "url" | "richtext" | "text" | "number" | "boolean" | "unknown" | `custom_${string}`;

其中custom_${string}由各 UI 包的自定义 Inferencer 组件在拥有专属展示形式时使用,目前用户还不能向 Inferencer 组件传入自定义类型与推断函数。

对象类型属性的代表键(PresentationalKeys

type PresentationalKeys = | "name" | "label" | "title" | "count" | "content" | "username" | "nickname" | "login" | "firstName" | "lastName" | "url";

选键逻辑在 packages/inferencer/src/utilities/get-fieldable-keys 中实现,并且与字段名本身相关——比如字段名本身就叫name时会有更高命中倾向,仓库为该工具编写了独立测试 get-fieldable-keys/index.test.ts。

关系字段如何判定

在判定一个字段是否可能为relation前,会先检查以下条件(这些检查不会触发任何 API 调用):

  • 属性名以idids结尾,camelCase、PascalCase、snake_case、kebab-case、UPPER_CASE、lower_case 均支持,且带或不带数组括号[]均可——对应实现见 packages/inferencer/src/field-inferencers/relation.ts,其正则/(-id|-ids|_id|_ids|Id|Ids|ID|IDs)(\[\])?$/用于识别这类命名;
  • 属性是仅含单个id键的对象;
  • 属性是仅含单个id键的对象的数组,或由 UUID 兼容字符串/数字组成的数组;
  • 属性是字符串或数字,且属性名与某个已知资源名(单数或复数)匹配。

一旦命中上述任一条件,该字段即被视为relation类型,随后按以下顺序确定关联资源:

  1. 首先尝试在resources数组中找到与属性名(单数或复数)匹配的资源;
  2. 找到匹配资源,则直接使用该资源作为关联资源;
  3. 未找到时,向defaultdataProvider发送两次请求,分别使用去除id后缀后的单数与复数属性名;
  4. 若找到资源,则使用该资源及其指定的dataProvider,用属性值发起 API 调用;
  5. 任一请求返回200状态码,即确认该属性为relation类型并绑定关联资源;
  6. 若全部请求失败,则移除该属性的relation标记、视为普通字段;若是对象类型,则退回选择最合适的代表键。

需要说明的是,条件 3 中的探测请求发生在你的应用运行时(Inferencer 组件内部),并不会修改你的后端数据。

关系资源的最终绑定由字段转换器完成,见 packages/inferencer/src/field-transformers:其中 relation-by-resource.ts 调用resourceFromInferred从现有resources中解析匹配资源;basic-to-relation.ts 处理基本值字段向关系字段的转换;relation-to-fieldable.ts 负责将关系字段的展示键(fieldable)信息回填;image-by-key.ts 则根据键名把image类型的字段识别出来。

手动设置关系与资源

如果你的dataProviderresources的工作方式特殊,导致 Inferencer 无法自动找到关联资源,可以通过fieldTransformer函数手动修改推断字段,详见下文「修改推断字段」小节。

组件渲染与代码生成

组件渲染使用带 TypeScript 支持的react-live分支(fork 自 FormidableLabs 的react-live)。字段确定后,由renderer函数生成组件代码,同一份代码既用于页面上的实时渲染,也展示给用户复制。rendereraction 类型 × UI 包组合构建,因此@refinedev/inferencer/antd等各 UI 作用域分别有listshoweditcreate四套渲染器——例如 Ant Design 的列表渲染器在 packages/inferencer/src/inferencers/antd/list.tsx,编辑渲染器在 packages/inferencer/src/inferencers/antd/edit.tsx。

renderer返回包含组件代码的字符串,展示给用户复制使用;同一字符串也会交给react-live在视图中渲染。从 list.tsx 可以看到组件命名规则:组件名由当前resource元素与当前 action 决定,若资源配置了option.label(或meta.label),则使用该 label 作为组件名的一部分,否则使用resource.name。例如资源名为categories、action 为list,则组件名为CategoryList(单复数与大小写转换由 utilities/component-name 处理,并配有对应测试 component-name/index.test.ts)。

以列表页为例,Ant Design 渲染器会按字段类型映射为不同的表格列:

  • text/number:普通Table.Column(多值时用TagField);
  • richtextMarkdownField,截取前 80 个字符展示;
  • emailEmailField
  • imageImageField(多值字段逐个渲染);
  • dateDateField
  • booleanBooleanField
  • urlUrlField
  • relation:生成useMany查询代码,将 id 数组映射为关联资源数据后展示(多值时用TagField,单值时展示关联记录的代表键)。

同时,渲染器会根据资源的editshowdelete权限(含resource.meta.canEdit/canShow/canDelete)自动追加EditButtonShowButtonDeleteButton操作列。

与 GraphQL 后端及meta值配合

refine 通过数据 hooks 中的meta属性处理 GraphQL 等后端。Inferencer 允许你在单个 prop中为多个资源与方法定义 meta 值,并会把它用于代码生成与字段推断。与数据 hooks 的meta不同,Inferencer 组件的meta采用嵌套结构,可按资源与 action 分别定义:

<AntdListInferencer meta={{ [resourceNameOrIdentifier: string]: { [methodName: "default" | "getList" | "getMany" | "getOne" | "update"]: Record<string, unknown>, } }} />

其中default是该资源所有方法的默认 meta 值;当某方法没有专属 meta 值时,将回退使用default。这一设计是为了让用户在 Inferencer 可能发现关系字段并发起多个 hook 请求时,能够一次性为多个资源与动作提供 meta 值。对应的类型定义在 packages/inferencer/src/types/index.ts(支持getListgetManygetOneupdatecreatedefault)。

示例

<AntdListInferencer meta={{ posts: { getList: { fields: ["id", "title", "content", "category_id", "created_at"], }, }, categories: { default: { fields: ["id", "title"], }, }, }} />

在渲染器内部,meta 值通过getMetaProps工具(packages/inferencer/src/utilities/get-meta-props)按资源标识符与所需方法取出,拼接到生成的useTableuseMany等 hook 调用中;同时,渲染器会检测 meta 中是否含gqlQuery/gqlMutation键,若有则自动在生成的代码里引入gql(来自graphql-tag)。

修改推断字段:fieldTransformer

若想自定义 Inferencer 的输出——例如为object类型字段设置自定义accessor、修改字段type、或更改relation类型的关联资源——可使用 Inferencer 组件的fieldTransformerprop。它是一个函数:接收字段作为参数,返回修改后的字段;若返回undefined | false | null,该字段将从输出中移除(预览与代码中均不出现)。

<AntdShowInferencer fieldTransformer={(field) => { // 隐藏不想展示的字段 if (field.key === "internal_note") { return undefined; } // 修改字段的 accessor if (field.key === "author" && field.type === "object") { return { ...field, accessor: "fullName", }; } return field; }} />

在 create-inferencer/index.tsx 的实现中,fieldTransformer会在默认转换器(defaultTransformers,见 packages/inferencer/src/field-transformers/index.ts)之后逐字段执行,其返回值决定该字段是否保留以及以何种形态进入渲染器。除 prop 形式外,createInferencer工厂还支持通过配置中的fieldTransformers数组注入批量转换器,供二次开发 UI 包时使用。

隐藏代码查看器与开发警告

生产环境中可使用hideCodeViewerInProductionprop 隐藏代码查看器与信息提示组件;该 prop 仅在生产模式下生效,开发模式下代码查看器与提示块始终可见:

<AntdListInferencer hideCodeViewerInProduction />

代码查看器组件为各 UI 包共享的SharedCodeViewer(packages/inferencer/src/components/shared-code-viewer),展示经过格式化的最终代码并提供复制按钮。

使用边界与注意事项

  • @refinedev/inferencer目前是实验性包,处于早期开发阶段,官方持续改进并添加新特性;
  • Inferencer 组件仅用于开发环境,用于帮助你生成组件代码,不应用于生产环境hideCodeViewerInProduction只隐藏代码查看器,并不改变这一性质;
  • 字段推断依赖真实数据:若某资源暂无数据,列表/创建视图的推断会失败并显示错误提示,此时需要先确保 dataProvider 能返回记录;
  • 关系判定中的探测请求会向默认 dataProvider 发起,涉及网络开销;若资源结构特殊导致自动判定失败,应使用fieldTransformer手动修正。

从源码深入:测试与快照

各 UI 包的 Inferencer 均配有完整测试与快照,可直接观察每种字段类型生成的最终代码形态,例如 Ant Design 的 list.test.tsx 及其快照 list.test.tsx.snap,MUI、Mantine、Chakra UI、Headless 各有对应的tests目录。工具层测试(如 field-inferencers/date.test.ts、utilities/accessor/index.test.ts)则验证了单个推断函数与取值工具的行为。阅读这些快照与测试,是理解「同一份数据在不同 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询