在 Formik 中使用 Material-UI 的自动完成组件
Using Material-UI's Autocomplete component with Formik
目前正在尝试将 Material UI 的 Autocomplete 组件与 Formik 一起使用。到目前为止,文本字段和 Material-UI 中的传统选择与 Formik 配合得非常好。实施自动完成并非如此。 Formik 的 onChange 处理程序似乎没有更新我的 city_id
的值。我知道自动完成仍然不属于 Material-UI 的核心库,但目前仍在查看是否有可能实现这样的功能。
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const initialValues = {
city_id: '',
};
const submit = params => {
alert(`Value for city_id is: ${params.city_id}`);
};
function App() {
return (
<Formik
initialValues={ initialValues }
onSubmit={ submit }
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
你的问题是 handleChange
不会按照你的方式工作。
如果你看一下 handleChange docs:
General input change event handler. This will update the values[key] where key is the event-emitting input's name attribute. If the name attribute is not present, handleChange will look for an input's id attribute. Note: "input" here means all HTML inputs.
应该可以正常工作,但问题是 Autocomplete
里面的 TextField
只会在您输入内容时触发 handleChange
,并且值将是文本,不是您想要的 id
或其他 属性,因此您需要将 handleChange
移动到 Autocomplete
。
还有一个问题,你不能在Autocomplete
中使用handleChange
,因为它没有引用你想要的输入,而且它的参数也不同于普通的[=20] =] 的 input
,如您在 docs.
中所见
onChange
func
Callback fired when the value changes.
Signature:
function(event: object, value: any) => void
event
: The event source of the callback
value
: null
所以你需要做的是使用 setFieldValue
并将其传递给 Autocomplete
就像
onChange={(e, value) => setFieldValue("city_id", value)}
你需要传递你的字段名称和你想要得到的值。
这是一个working example
@vencovsky 提供的正确答案对我仍然有效 Material UI 14.10.1.
我要添加更多内容,因为我在使用 Yup
验证时将字段设置为 required
。
为了让它正常工作,我有以下内容:
Yup
配置:
validationSchema = {
Yup.object().shape({
contact: Yup.string().max(255).required('Contact is required'),
})
}
反应:
<Autocomplete
id="contact-autocomplete"
options={contacts}
getOptionLabel={(contact) => `${contact?.firstName} ${contact?.lastName}`}
onChange={(e, value) => setFieldValue("contact", value?.id || "")}
onOpen={handleBlur}
includeInputInList
renderInput={(params) => (
<TextField
{...params}
error={Boolean(touched.contact && errors.contact)}
fullWidth
helperText={touched.contact && errors.contact}
label="Contact Person"
name="contact"
variant="outlined"
/>
)}
/>
当用户单击 Autocomplete
元素时,它会触发运行 Formik
onBlur
的 onOpen
并将字段标记为已触摸。如果没有选择一个项目,Formik flags
字段并显示 Contact is required
验证消息。
您必须在 Autocomplete
标签中添加 onChange = {(event, value) => handleChange(value)}
作为
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const [cityId,setCityId]=React.useState({city_id:''});
const handleChange=(value)=>{
// Here is the value is a selected option label or the new typed value
setCityId({city_id:value});
}
function App() {
return (
<Formik
initialValues={ cityId }
onSubmit={() => {
alert(`Value for city_id is: ${cityId.city_id}`);
}}
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
onChange = {(event, value) => handleChange(value)}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果 onChange 不起作用,您也可以使用 onInputChange。
目前正在尝试将 Material UI 的 Autocomplete 组件与 Formik 一起使用。到目前为止,文本字段和 Material-UI 中的传统选择与 Formik 配合得非常好。实施自动完成并非如此。 Formik 的 onChange 处理程序似乎没有更新我的 city_id
的值。我知道自动完成仍然不属于 Material-UI 的核心库,但目前仍在查看是否有可能实现这样的功能。
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const initialValues = {
city_id: '',
};
const submit = params => {
alert(`Value for city_id is: ${params.city_id}`);
};
function App() {
return (
<Formik
initialValues={ initialValues }
onSubmit={ submit }
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
你的问题是 handleChange
不会按照你的方式工作。
如果你看一下 handleChange docs:
General input change event handler. This will update the values[key] where key is the event-emitting input's name attribute. If the name attribute is not present, handleChange will look for an input's id attribute. Note: "input" here means all HTML inputs.
应该可以正常工作,但问题是 Autocomplete
里面的 TextField
只会在您输入内容时触发 handleChange
,并且值将是文本,不是您想要的 id
或其他 属性,因此您需要将 handleChange
移动到 Autocomplete
。
还有一个问题,你不能在Autocomplete
中使用handleChange
,因为它没有引用你想要的输入,而且它的参数也不同于普通的[=20] =] 的 input
,如您在 docs.
onChange
func
Callback fired when the value changes.
Signature:
function(event: object, value: any) => void
event
: The event source of the callback
value
: null
所以你需要做的是使用 setFieldValue
并将其传递给 Autocomplete
就像
onChange={(e, value) => setFieldValue("city_id", value)}
你需要传递你的字段名称和你想要得到的值。
这是一个working example
@vencovsky 提供的正确答案对我仍然有效 Material UI 14.10.1.
我要添加更多内容,因为我在使用 Yup
验证时将字段设置为 required
。
为了让它正常工作,我有以下内容:
Yup
配置:
validationSchema = {
Yup.object().shape({
contact: Yup.string().max(255).required('Contact is required'),
})
}
反应:
<Autocomplete
id="contact-autocomplete"
options={contacts}
getOptionLabel={(contact) => `${contact?.firstName} ${contact?.lastName}`}
onChange={(e, value) => setFieldValue("contact", value?.id || "")}
onOpen={handleBlur}
includeInputInList
renderInput={(params) => (
<TextField
{...params}
error={Boolean(touched.contact && errors.contact)}
fullWidth
helperText={touched.contact && errors.contact}
label="Contact Person"
name="contact"
variant="outlined"
/>
)}
/>
当用户单击 Autocomplete
元素时,它会触发运行 Formik
onBlur
的 onOpen
并将字段标记为已触摸。如果没有选择一个项目,Formik flags
字段并显示 Contact is required
验证消息。
您必须在 Autocomplete
标签中添加 onChange = {(event, value) => handleChange(value)}
作为
import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form } from 'formik';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import Button from '@material-ui/core/Button';
import { cities } from '../data/cities';
import "./styles.css";
const [cityId,setCityId]=React.useState({city_id:''});
const handleChange=(value)=>{
// Here is the value is a selected option label or the new typed value
setCityId({city_id:value});
}
function App() {
return (
<Formik
initialValues={ cityId }
onSubmit={() => {
alert(`Value for city_id is: ${cityId.city_id}`);
}}
>
{({
handleChange,
values,
}) => (
<Form>
<Autocomplete
id="city_id"
name="city_id"
options={ cities }
groupBy={ option => option.state }
getOptionLabel={ option => option.name }
style={{ width: 300 }}
onChange = {(event, value) => handleChange(value)}
renderInput={params => (
<TextField
{ ...params }
onChange={ handleChange }
margin="normal"
label="Cities"
fullWidth
value={ values.city_id }
/>
)}
/>
<Button
variant="contained"
color="primary"
type="submit"
>
Submit
</Button>
</Form>
)}
</Formik>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果 onChange 不起作用,您也可以使用 onInputChange。