
react-admin 的RecordField组件完全指南标签 字段值的一体化渲染方案【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-adminRecordField是 react-admin 中一个轻量但实用的展示型组件它把字段标签与字段值打包成一个组件默认基于source自动生成人性化标签并从当前RecordContext中取出记录渲染字段值。本文将从用法、全部 Props、与field/children/render三种渲染方式的关系、国际化标签、内联布局与主题定制等角度展开并深入packages/ra-ui-materialui/src/field/RecordField.tsx源码与单元测试帮助你在Show、Edit、ReferenceField等场景中灵活、正确地使用它。核心用法RecordField必须在提供RecordContext的组件内部使用例如记录详情类组件Show、Edit、ReferenceField、ReferenceOneField。例如在 Show 视图中渲染一本书的标题import { Show, RecordField } from react-admin; import { Stack } from mui/material; export const BookShow () ( Show Stack RecordField sourcetitle / /Stack /Show );其渲染流程是RecordField根据source或labelprop渲染一个标签同时从当前RecordContext中取出record提取record[source]的值默认交给TextField显示。从源码看RecordField.tsx组件内部通过useRecordContextRecordType(props)获取记录该 Hook 的实现是(props props.record) || context即显式传入的recordprop 优先级高于上下文见 useRecordContext.ts。此外若既没有source也没有label组件会直接返回null不会渲染任何内容。你可以通过labelprop 覆盖自动生成的标签RecordField sourcetitle labelBook title /source支持深层字段路径deep source例如渲染嵌套对象author.nameRecordField labelAuthor name sourceauthor.name /如果你想自定义值的显示方式可以传入一个 Field 组件作为fieldprop。例如用浏览器 locale 格式化数字使用NumberFieldimport { RecordField, NumberField } from react-admin; RecordField sourceprice field{NumberField} /如果需要给字段组件传特定 props例如格式化货币优先把字段组件作为children传入。此时传给RecordField的source仅用于生成标签import { RecordField, NumberField } from react-admin; RecordField sourceprice NumberField sourceprice options{{ style: currency, currency: USD }} / /RecordField如果需要聚合多个字段可以用renderprop 传入一个接收当前 record、返回 React 元素的函数import { RecordField } from react-admin; RecordField labelName render{record ${record.firstName} ${record.lastName}} /注意field、children、render三个 prop 互斥。从源码的渲染优先级看它们是children render field source默认 TextField的递进关系后设置的会被前面的覆盖。Props 一览PropRequiredTypeDefaultDescriptionchildrenOptionalReactNodeElements rendering the actual field.classNameOptionalstringCSS class name to apply to the field.emptyOptionalReactNodeText to display when the field is empty.fieldOptionalReactElementTextFieldField component used to render the field. Ignored ifchildrenorrenderare set.labelOptionalstringLabel to render. Can be a translation key.recordOptionalobject{}Record to use. If not set, the record is taken from the context.renderOptionalrecord JSXFunction to render the field value. Ignored ifchildrenis set.sourceOptionalstringName of the record field to render.sxOptionalobject{}Styles to apply to the field.TypographyPropsOptionalobject{}Props to pass to label wrappervariantOptionaldefault || inlinedefaultWheninline, the label is displayed inline with the field value.源码提示RecordFieldProps实际继承自 MUI 的StackProps见 RecordField.tsx因此任何Stack支持的布局类 prop 都可以直接透传给RecordField。另外组件内部通过useThemeProps({ props: inProps, name: RaRecordField })启用主题体系这也是后文通过主题定制默认variant能够生效的底层原因。children自定义渲染的字段组件children用于传入一个字段组件替换默认的渲染方式。此时source仅用于生成标签import { RecordField, NumberField } from react-admin; RecordField sourceprice NumberField sourceprice options{{ style: currency, currency: USD }} / /RecordField这一能力经常被用来渲染来自引用reference记录的字段配合ReferenceFieldimport { RecordField, ReferenceField } from react-admin; RecordField labelAuthor ReferenceField sourceauthor_id referenceusers / /RecordField如果只是需要一个无特殊 props 的字段组件优先使用fieldprop代码更简洁import { RecordField, NumberField } from react-admin; RecordField sourceprice field{NumberField} / // instead of RecordField sourceprice NumberField sourceprice / /RecordField源码中children分支会把子元素包在一个span.RaRecordField-value中见 RecordField.tsx字段值区域默认flex: 1便于与标签对齐排版。Story 示例Children还展示了如何在子元素里拼接普通Typography文本RecordField.stories.tsx。empty空值占位当record[source]为空时RecordField默认渲染空字符串。如果希望显示自定义内容使用emptypropRecordField sourcetitle emptyMissing title /empty也接受翻译 key从而在字段为空时展示本地化文案RecordField sourcetitle emptyresources.books.fields.title.missing /如果使用renderprop你甚至可以把 React 元素作为empty值RecordField sourcetitle empty{span style{{ color: red }}Missing title/span} render{record record.title} /注意当你以子组件方式传入自定义字段组件时empty会被忽略此时空值处理由子组件自己负责RecordField labeltitle TextField sourcetitle emptyTextMissing title / /RecordField从源码可以看清empty的三种落地方式RecordField.tsxrender分支当render(record)的返回值为空时若empty是字符串则调用translate(empty, { _: empty })翻译否则原样渲染empty元素field分支empty被转换成emptyTextprop 传给字段组件source分支empty同样作为emptyText传给默认的TextField而TextField内部会再次执行translate(emptyText, { _: emptyText })见 TextField.tsx。单元测试对这三种路径均有覆盖RecordField.spec.tsxrecord 为undefined时渲染翻译后的 No titlerender模式下渲染 Unknown authorfield模式下渲染数字字段的 0。field替换默认的 TextField默认情况下RecordField使用TextField渲染字段值RecordField sourcetitle / // equivalent to RecordField sourcetitle field{TextField} /使用fieldprop 传入自定义字段组件import { RecordField, NumberField } from react-admin; RecordField sourceprice field{NumberField} /如需给字段组件传 props例如格式化货币优先将字段组件作为children此时source只用于标签import { RecordField, NumberField } from react-admin; RecordField sourceprice NumberField sourceprice options{{ style: currency, currency: USD }} / /RecordField源码中field分支通过React.createElement(field, { source, emptyText: empty as string, className: RecordFieldClasses.value })实例化该组件RecordField.tsx自动把source、empty作为emptyText和值区域的 class 传入无需手工重复声明。label标签的自动生成与覆盖当使用sourceprop 时标签会自动根据 source 名经 humanize 处理生成。例如author.name会显示为 Author name。你还可以通过为resources.${resourceName}.fields.${source}key 配置翻译文案来定制标签。例如资源posts下要为RecordField sourcetitle /定制标签添加如下翻译{ resources: { posts: { fields: { title: Post title } } } }若未使用source或不希望借助 i18N 定制标签可以用labelprop 覆盖默认标签RecordField sourcetitle labelPost title /label也可以传翻译 keyreact-admin 会通过i18nProvider翻译RecordField sourcetitle labelresources.posts.fields.title_custom /最后传false可以隐藏标签RecordField sourcetitle label{false} /注意label{false}等价于直接渲染一个TextField此时不再有标签包装层。结合源码可以更深入地理解标签解析链路标签最终由FieldTitle渲染FieldTitle.tsx它调用useTranslateLabel后者通过getFieldLabelTranslationArgs生成resources.${resource}.fields.${source}这样的翻译 keyuseTranslateLabel.ts。在RecordField内部label为空字符串或false时整个Typography标签包装层都会被跳过RecordField.tsx。测试用例也验证了默认渲染 humanized 的 Title、labelprop 覆盖为 Identifier、label{false}时页面中不再出现 SummaryRecordField.spec.tsx。record覆盖上下文记录默认情况下RecordField使用当前RecordContext中的记录。你也可以通过recordprop 覆盖RecordField record{record} sourcetitle /这与useRecordContext的实现一致return (props props.record) || context;useRecordContext.ts即 prop 优先、context 兜底。render聚合多字段或使用任意组件renderprop 接收当前 record 并返回 React 元素适合聚合多个字段或使用不接受sourceprop 的组件import { RecordField } from react-admin; RecordField labelName render{record ${record.firstName} ${record.lastName}} /如果同时传source和rendersource仅用于标签。源码中render分支在record存在时才渲染并把结果包进Typography componentspan variantbody2RecordField.tsx当返回值为空时按上文所述回退到empty。测试覆盖了字符串返回值如大写标题、React 元素返回值以及 record 为undefined时不抛错RecordField.spec.tsx。sx样式定制使用sxprop 给整个字段传自定义样式RecordField sourceid sx{{ opacity: 0.5 }} /若要单独给标签加样式使用TypographyPropsRecordField sourceid TypographyProps{{ sx: { color: red } }} /若只想给值加样式优先把自定义组件作为 childrenRecordField sourceid TextField sourceid sx{{ color: red }} / /RecordField底层上sx作用于包裹根节点的styled(Stack)而标签与值分别使用.RaRecordField-label与.RaRecordField-value两个内部 classRecordField.tsx因此你也可以像 StorySX那样用后代选择器单独命中标签RecordField sourceyear field{NumberField} sx{{ .RaRecordField-label: { color: red } }} /source要渲染的字段名使用sourceprop 指定要渲染的记录字段名。例如当前 record 为{ id: 123, title: My post, author: { name: John Doe } }显示title字段RecordField sourcetitle /source可以是深层路径例如author.nameRecordField sourceauthor.name /如果同时使用render或childrenpropsource仅用于生成标签。深层路径提示RecordField sourceauthor.name /依赖底层TextField的useFieldValue能力去解析点分路径而当 record 中恰好存在一个 key 就叫author.name时StorySource中的行为也验证了这一点RecordField.stories.tsx。实践中请留意数据结构的实际形态。TypographyProps标签包装层属性TypographyProps用于给标签包装层传 props便于让标签的样式与字段值区分开RecordField sourceid TypographyProps{{ sx: { color: red } }} /从源码看该 prop 会被透传给承载FieldTitle的Typography元素RecordField.tsx所以TypographyProps里除了sx还可以传 MUI Typography 支持的任何属性如variant、color等。variant默认布局与内联布局默认情况下RecordField将标签渲染在字段值上方。使用variantinline可将标签与字段值同行显示RecordField sourcetitle variantinline /如果需要定制标签宽度使用TypographyPropsRecordField sourcetitle variantinline TypographyProps{{ sx: { width: 200 } }} /但由于通常需要对多个字段统一设置推荐在父组件中统一处理Stack sx{{ .RaRecordField-label: { width: 200 } }} RecordField variantinline sourceid / RecordField variantinline sourcetitle / RecordField variantinline sourceauthor / RecordField variantinline sourcesummary / RecordField variantinline sourceyear field{NumberField} / /Stack提示如果希望所有字段都默认内联显示可以在自定义应用主题中为RaRecordField定义默认variant详见主题化单个组件import { defaultTheme } from react-admin; import { deepmerge } from mui/utils; const theme deepmerge(defaultTheme, { components: { RaRecordField: { defaultProps: { variant: inline, }, }, }, }); const App () ( Admin theme{theme} // ... /Admin );从源码可以看到内联布局的底层实现variant inline时根节点追加.RaRecordField-inlineclass样式将根Stack的flexDirection切换为row同时内联状态下标签字号调整为0.875rem、display: block、默认minWidth: 150RecordField.tsx。此外组件通过declare module mui/material/styles注册了RaRecordField的defaultProps与styleOverrides类型声明RecordField.tsx这正是主题化定制能获得类型提示的原因。TypeScript泛型类型安全RecordField是一个泛型组件。你可以传入类型参数从而获得sourceprop 的补全提示以及render函数中record参数的类型安全import { Show, RecordField } from react-admin; import { Stack } from mui/material; import { Book } from ./types; const BookShow () { const BookField RecordFieldBook; return ( Show Stack BookField sourcetitle / BookField sourceauthor.name / BookField sourceprice render{record ${record.price} USD} / /Stack /Show ); };从类型定义看RecordField.tsxRecordType默认是Recordstring, anysource的类型被限定为NoInferHintedStringExtractRecordPathsRecordType即根据记录类型提取出的字段路径的补全字符串render的函数签名则为(record: RecordType) React.ReactNode。StoryGeneric中给出了完整可运行的泛型示例RecordField.stories.tsx。小结与使用建议RecordField把标签 值这一最常见的信息展示模式封装为一个组件适合在Show、Edit、ReferenceField等记录上下文中快速搭建只读展示界面。使用时建议遵循以下取舍仅需展示单字段 → 用source默认TextField渲染需换字段组件且无额外 props → 用field如field{NumberField}需给字段组件传格式化等 props或渲染引用字段 → 用children需聚合多字段或接入不接受source的组件 → 用render空值展示 → 用empty支持翻译 key 与 React 元素批量内联布局 → 在父组件统一设置sx或在应用主题中为RaRecordField设置默认variant。相关阅读TextField、ReferenceField、RecordContext与useRecordContext、字段组件总览。【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考