React-Admin抽离表单子组件后TextField无值、TextInput样式丢失
嘿,我看你在React-Admin里拆分复用表单组件时遇到了两个头疼的问题:TextField无法显示值和TextInput样式丢失,这俩都是复用组件时常见的坑,我来帮你一步步搞定它们。
问题1:TextField无法显示值
为啥会这样?
TextField是React-Admin专门给Show页面设计的组件,它依赖ShowContext来自动读取当前记录(record)。但在SimpleForm内部,上下文是FormContext,根本不会给TextField传递record,所以它自然拿不到值。
另外,在编辑场景下用TextField其实不太合适——React-Admin有专门的DisabledInput组件,既可以展示不可编辑的内容,又能完美适配表单的上下文环境。
怎么解决?
方案A:改用DisabledInput(强烈推荐)
把你的TextField替换成DisabledInput,它会自动从表单上下文获取值,样式还能和其他输入组件保持统一:
{props.componentType === 'edit' && ( <> <DisabledInput source="id" label="Id" /> <DisabledInput source="organization_id" label="Organization" /> <DisabledInput source="provider" label="Provider" /> </> )}
方案B:手动给TextField传record
如果你非要保留TextField,可以通过FormDataConsumer获取表单里的record,然后手动传给它:
{props.componentType === 'edit' && ( <FormDataConsumer> {({ record }) => ( <> <TextField record={record} source="id" label="Id" /> <TextField record={record} source="organization_id" label="Organization" /> <TextField record={record} source="provider" label="Provider" /> </> )} </FormDataConsumer> )}
问题2:TextInput的CSS样式丢失
可能的原因
样式丢失一般有两种情况:
- 你自定义的
utilStyles没有正确传递给组件,或者样式类的优先级不够; - React-Admin的Input组件是基于MUI的
FormControl封装的,直接加className可能不生效,得用特定的props传递样式。
解决方案
1. 先确认样式定义没问题
检查你的utilStyles是不是用MUI的makeStyles正确定义的:
import { makeStyles } from '@material-ui/core/styles'; const utilStyles = makeStyles({ fullWidth: { width: '100%', marginBottom: '1rem', // 可选,和其他表单组件保持一致的间距 }, });
2. 用formControlProps传递样式
React-Admin的Input组件需要通过formControlProps来传递容器样式,而不是直接给Input加className:
<TextInput source="description" label={'Description *'} formControlProps={{ className: classes.fullWidth }} options={{ multiLine: true }} />
3. 修复ArrayInput内组件的样式
对于ArrayInput里的AutocompleteInput,同样用formControlProps传递样式:
<ReferenceInput source="questionId" label="Question" reference="search-questions" formControlProps={{ className: classes.fullWidth }} > <AutocompleteInput optionValue="id" matchSuggestion={() => true} inputText={(value) => value?.question_text?.slice(0, 200)} optionText={<Custom/>} /> </ReferenceInput>
额外的小修正
我注意到你代码里有个命名笔误:CommonComponents和CommonComponent不一致,记得把它们统一,不然可能会出现组件不渲染的问题:
// 把CommonComponents改成CommonComponent export const AssessmentEdit = props => { return ( <CommonComponent {...props} componentType='edit' notif='Assessment Preference Updated successfully' redirect='list' validation={validateAssessment}> <FormData {...props} componentType='edit'/> </CommonComponent> ); };
最终修改后的FormData组件示例
export const FormData = (props) => { const classes = utilStyles(); return ( <React.Fragment> {props.componentType === 'edit' && ( <> <DisabledInput source="id" label="Id" /> <DisabledInput source="organization_id" label="Organization" /> <DisabledInput source="provider" label="Provider" /> </> )} <TextInput source="name" label={'Name *'}/> <SelectInput source="category" label={'Category *'} choices={AssessmentCategory} optionText="name" optionValue="value"/> <ArrayInput source="topics"> <SimpleFormIterator> <TextInput/> </SimpleFormIterator> </ArrayInput> <TextInput source="description" label={'Description *'} formControlProps={{ className: classes.fullWidth }} options={{multiLine: true}} /> <RichTextInput source="instructions" label={'Instructions *'}/> <NumberInput source="duration" label={'Duration *'}/> <BooleanInput source="randomize_questions"/> <FormDataConsumer> {({formData: {randomize_questions}}) => { if (randomize_questions) { return <NumberInput source="question_count" label={'Question Count *'}/> } return null; }} </FormDataConsumer> <ArrayInput source="questions" label={'Questions *'}> <SimpleFormIterator> <ReferenceInput source="questionId" label="Question" reference="search-questions" formControlProps={{ className: classes.fullWidth }} > <AutocompleteInput optionValue="id" matchSuggestion={() => true} inputText={(value) => value?.question_text?.slice(0, 200)} optionText={<Custom/>} /> </ReferenceInput> <NumberInput label="Question Weight" source="question_weight"/> </SimpleFormIterator> </ArrayInput> <ArrayInput source="skills" label={'Skills *'}> <SimpleFormIterator> <ReferenceInput source="skillId" label="Skill" reference="perform-skill-search" formControlProps={{ className: classes.fullWidth }} > <AutocompleteInput optionValue="id" optionText="display_name"/> </ReferenceInput> <SelectInput label="Skill Level" choices={levels} optionText="key" optionValue="value" source="skill_level"/> </SimpleFormIterator> </ArrayInput> </React.Fragment> ); };
内容的提问来源于stack exchange,提问作者Atishay Khare

