我有一个自定义的 Material UI 多选输入,其中的自定义部分允许它预先填充初始值,从数据库中检索(它将它们加载为输入中的选定项),然后是一个名为
handleChange
的函数允许用户编辑所选元素(取消选择/删除已加载的元素,和/或添加新元素)。
这一切都按照我需要的方式在屏幕上呈现。我的问题是当我点击提交按钮时输出的内容。
代码:
import {
FormControl,
InputLabel,
ListItemText,
MenuItem,
OutlinedInput,
Select,
Button,
} from '@mui/material';
import React from 'react';
import { Formik } from 'formik';
export default function Notifications() {
const usersList = [
{ id: 1, FullName: 'Name1' },
{ id: 2, FullName: 'Name2' },
{ id: 3, FullName: 'Name3' },
{ id: 4, FullName: 'Name4' },
{ id: 5, FullName: 'Name5' },
];
const [personName, setPersonName] = React.useState([
{ id: 2, FullName: 'Name2' },
{ id: 4, FullName: 'Name4' },
]);
const submit = values => {
console.log('values', values);
};
const handleChange = (event) => {
const fullName = event.target.value.slice(-1).pop();
const selectedPerson = usersList.find((u) => u.FullName === fullName);
if (
selectedPerson &&
!personName.some((person) => person.FullName === fullName)
) {
setPersonName((prevArray) => [...prevArray, selectedPerson]);
} else {
const updatedArray = personName.filter((p) => p.FullName !== fullName);
console.log('updatedArray', updatedArray);
setPersonName((prevArray) => [...updatedArray]);
}
console.log('event.target.value', event.target.value);
console.log('personName', personName);
};
return (
<Formik onSubmit={submit}>
{({ values, setFieldValue }) => (
<div>
<FormControl sx={{ m: 1, width: 210 }} size="small">
<InputLabel id="demo-multiple-checkbox-label">Users</InputLabel>
<Select
labelId="demo-multiple-checkbox-label"
id="demo-multiple-checkbox"
multiple
value={personName}
onChange={handleChange}
input={<OutlinedInput label="Users" />}
renderValue={(selected) => {
return selected.map((s, index) => (
<div key={index}>
<MenuItem key={'menuItem' + index} value={s.id}>
<ListItemText
key={'listItemText' + index}
primary={s.FullName}
/>
</MenuItem>
</div>
));
}}
>
{usersList.map((name) => {
return (
<MenuItem key={name.id} value={name.FullName}>
<ListItemText primary={name.FullName} />
</MenuItem>
);
})}
</Select>
<Button variant="contained" color="primary" type="submit">
Submit
</Button>
</FormControl>
</div>
)}
</Formik>
);
}
我需要将它与 Formik 集成,但我真的很挣扎(现在已经尝试了几天的挣扎)。当按下提交按钮时,它被设置为记录
values
的内容(我相信根据文档here,这应该是 Formik values prop 的正确名称)。
我认为它需要使用 Formik
setFieldValue
道具,也许是从现有的 onChange
道具(目前调用自定义“handleChange”函数)调用它,但我不是 100% 确定,我在如果那是需要发生的事情,那么对于如何做到这一点感到茫然。
经过大量的试验和错误,我设法让它做我需要的事情——选择字段预先填充了初始值,然后用户可以编辑其内容,并将选定的值传递给 Formik 的
value
道具。这是通过结合使用 useFormik
钩子、<Formik/>
组件的 setFieldValue
道具和 <Formik/>
组件的 initialValues
道具来实现的。
希望下面的内容可以帮助将来的其他人,因为 Formik 和 MUI 文档非常有限,这使得这类事情变得非常具有挑战性。顺便说一句,我注意到开发人员不再支持 Formik,所以如果有人在 2023 年 4 月之后阅读这篇文章并且刚刚开始(即尚未对 Formik 投入大量开发工作),那么最好请改用其他库。
新代码
import {
FormControl,
InputLabel,
ListItemText,
MenuItem,
OutlinedInput,
Select,
Button,
} from '@mui/material';
import React, { useEffect } from 'react';
import { useFormik } from 'formik';
export default function Notifications() {
const usersList = [
{ id: 1, FullName: 'Name1' },
{ id: 2, FullName: 'Name2' },
{ id: 3, FullName: 'Name3' },
{ id: 4, FullName: 'Name4' },
{ id: 5, FullName: 'Name5' },
];
const [personName, setPersonName] = React.useState([
{ id: 2, FullName: 'Name2' },
{ id: 4, FullName: 'Name4' },
]);
const formik = useFormik({
initialValues: {
members: personName,
},
onSubmit: (values) => {
console.log('values', values);
},
});
// This is needed to update the formik values prop every time personName changes - without this is doesn't update
useEffect(() => {
formik.setFieldValue('members', personName);
}, [personName]);
const handleChange = (event) => {
const fullName = event.target.value.slice(-1).pop();
const selectedPerson = usersList.find((u) => u.FullName === fullName);
console.log('fullName', fullName)
if (
selectedPerson &&
!personName.some((person) => person.FullName === fullName)
) {
setPersonName((prevArray) => [...prevArray, selectedPerson]);
} else {
const updatedArray = personName.filter((p) => p.FullName !== fullName);
console.log('updatedArray', updatedArray);
setPersonName(updatedArray);
}
console.log('event.target.value', event.target.value);
console.log('personName', personName);
};
return (
<div>
<FormControl sx={{ m: 1, width: 210 }} size="small">
<InputLabel id="multiple-checkbox-label">Members</InputLabel>
<Select
labelId="multiple-checkbox-label"
id="multiple-checkbox"
multiple
value={personName.map((p) => p.FullName)}
//value={personName}
onChange={handleChange}
input={<OutlinedInput label="Members" />}
renderValue={(selected) => {
return selected.map((s, index) => (
<div key={index}>
<MenuItem key={'menuItem' + index} value={s}>
<ListItemText
key={'listItemText' + index}
primary={s}
/>
</MenuItem>
</div>
));
}}
>
{usersList.map((name) => {
return (
<MenuItem key={name.id} value={name.FullName}>
<ListItemText primary={name.FullName} />
</MenuItem>
);
})}
</Select>
<Button
variant="contained"
color="primary"
onClick={formik.handleSubmit}
>
Submit
</Button>
</FormControl>
</div>
);
}