我正试图在React Admin中构建一个名为"UserRolesSelect"的自定义输入字段的编辑表单,该字段显示来自一个单独角色端点的角色列表,其中当前用户的角色是选定的。但是,在发出编辑请求时,表单数据中不会更新自定义输入的值。我提供了上述两个端点的样本回复。
// sample response for getting user details by ID
const user = {
id:1,
name:'User1',
email:'user1@user.com',
created_at:2020-04-01T10:43:36.000000Z,
roles:[{id:1,name:'User'}]
};
// sample response of getting roles list
const roles = [
{id: 1,
name: 'user'},
{id: 2,
name: 'admin'}
]
const UserRolesSelect = ({ source, record }) => {
const [selectedRoles, setRoles] = useState([]);
useEffect(() => {
const userRoles = record.roles.map(role => role.id);
setRoles(userRoles);
}, []);
const { data, loading: rolesLoading, error: rolesError } = useQuery({
type: 'getList',
resource: 'roles',
});
if (rolesLoading) return <Loading />;
if (rolesError) return <Error />;
if (!data) return null;
const rolesList = data.map(role => <MenuItem key={role.id} value={role.id} selected={selectedRoles}>
{role.name}
</MenuItem>);
const handleChangeMultiple = event => {
const { value: role } = event.target;
const value = [...role];
setRoles(value);
};
return <Select
value={selectedRoles}
onChange={handleChangeMultiple}
multiple
>
{rolesList}
</Select>
};
const UserEdit = props => {
return <Edit {...props}>
<SimpleForm >
<TextInput source="name" />
<TextInput source="email" />
<UserRolesSelect source="roles"/>
</SimpleForm>
</Edit>
};
您的自定义元素会更新其内部状态,但不会将更改传达给外部世界。要更改表单值,必须使用<Field>
组件或useField()
挂钩-两者都来自react最终表单,即react管理员内部使用的form框架。
举个例子,这会给出类似于:
const UserRolesSelect = ({ source }) => {
const { input, meta } = useField(source);
// the current value is in input.value
// the callback to change the value is in input.onChange
...
};
react管理文档有一节详细解释了如何编写自定义表单,我建议您从阅读它开始
https://marmelab.com/react-admin/Inputs.html#writing-您自己的输入组件
此外,您似乎正在尝试重新创建react admin中已经存在的功能。请参阅ReferenceArrayInput的文档。
https://marmelab.com/react-admin/Inputs.html#referencearrayinput
也有完全相同的情况-需要一点时间才能开始以react管理风格思考,但之后看起来很漂亮。我建议采取以下策略:
在用户对象中保存一个角色id的数组。(为了方便起见,我可以在服务器上附加一个带有角色对象的数组(
const user = {
id:1,
name:'User1',
email:'user1@user.com',
created_at:2020-04-01T10:43:36.000000Z,
roles:[{id:1,name:'User'}, {id:2,name:'Manager'}],
rolesIds:[1, 2]
};
那么你应该使用以下组合:
<ReferenceArrayInput label="Roles" reference={"roles"} source="rolesIds">
<SelectArrayInput optionText={roleRender} />
</ReferenceArrayInput>
...
const roleRender = role => role.name;
通过这种方式,您可以从roles
端点收集一组选择,并将对象的数组rolesIds
中的内容标记为已选择。