我试图弄清楚如何遵循 Formik、Material UI、React 工具的 Autocomplete 字段的文档中的说明。
文档中给出的示例是:
import { Autocomplete } from 'formik-material-ui-lab';
const options = [{ title: 'The Shawshank Redemption', year: 1994 }, ...]
<Field
name="name"
component={Autocomplete}
options={options}
getOptionLabel={(option: Movie) => option.title}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['name'] && !!errors['name']}
helperText={errors['name']}
label="Autocomplete"
variant="outlined"
/>
)}
/>;
关于在 getOptionLabel 中使用 Movie 的含义,没有给出任何线索。当我尝试使用它时,Movie 带有下划线,就像 renderInput 对象中的 AutocompleteRenderInputParams 一样。我不知道为什么。
我看过这篇文章,它尝试了另一种方法,但我也无法让它发挥作用。
我有一个表格,有两个自动完成字段。目前,它看起来像这样。
当我尝试使用表单时,提交按钮挂起并且控制台日志显示:
Material-UI:
getOptionLabel
自动完成的方法返回 undefined 而不是 "" 的字符串。
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import firebase, {firestore} from '../../../firebase';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import {
Formik, Form, Field, ErrorMessage,
} from 'formik';
import * as Yup from 'yup';
import { Autocomplete, ToggleButtonGroup } from 'formik-material-ui-lab';
import { Switch } from 'formik-material-ui';
const styles = {
};
const allCategories = [
{value: 'culture', label: 'Culture'},
{value: 'other', label: 'Other'},
];
const sharingOptions = [
{value: 'open', label: 'Openly'},
{value: 'me', label: 'Only me'},
];
function Contact(props) {
const { classes } = props;
const [open, setOpen] = useState(false);
const [isSubmitionCompleted, setSubmitionCompleted] = useState(false);
function handleClose() {
setOpen(false);
}
function handleClickOpen() {
setSubmitionCompleted(false);
setOpen(true);
}
return (
<React.Fragment>
<Button
// component="button"
color="primary"
onClick={handleClickOpen}
style={{ float: "right"}}
variant="outlined"
>
Create an Impact Metric
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Create an Impact Metric</DialogTitle>
<DialogContent>
<DialogContentText>
test form.
</DialogContentText>
<Formik
initialValues={{ title: "", category: "", sharing: "" }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("testing").doc().set({
values,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
title: Yup.string()
.required('Required'),
category: Yup.string()
.required('Required'),
sharing: Yup.string()
.required('Required')
})}
>
{(props) => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Title"
name="title"
className={classes.textField}
value={values.title}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.title && touched.title) && errors.title}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Field
name="category"
component={Autocomplete}
options={allCategories}
getOptionLabel={option => option.label}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['category'] && !!errors['category']}
helperText={
touched['category'] && errors['category']
}
label="Select Category"
variant="outlined"
/>
)}
/>
</Box>
<Box margin={1}>
<Field
name="sharing"
component={Autocomplete}
options={sharingOptions}
getOptionLabel={option => option.label}
style={{ width: 300 }}
renderInput={(params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={touched['sharing'] && !!errors['sharing']}
helperText={
touched['sharing'] && errors['sharing']
}
label="Select Sharing Option"
variant="outlined"
/>
)}
/>
</Box>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</form>
);
}}
</Formik>
</DialogContent>
</React.Fragment>
}
{isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Thanks!</DialogTitle>
<DialogContent>
<DialogContentText>
test
</DialogContentText>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default withStyles(styles)(Contact);
任何人都可以看到如何根据上面链接中发布的文档来使用 formik、material ui 的自动完成功能吗?
我还尝试使用常规选择表单输入。这是表单域:
<Box margin={1}>
<Field
component={TextField}
type="text"
name="category"
label="Category"
select
variant="outlined"
helperText="Select a category"
margin="normal"
style={{ width: "100%"}}
InputLabelProps={{
shrink: true,
}}
>
{allCategories.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Field>
当我尝试这个时,我在控制台中收到一条警告,上面写着:
instrument.ts:129 Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''
此警告没有任何意义 - 表单以正确填充的菜单呈现。
我还收到一条错误消息:
index.js:1 警告:一个组件正在将 undefined 类型的不受控输入更改为受控。输入元素不应从不受控切换到受控(反之亦然)。决定在组件的生命周期内使用受控输入元素还是不受控输入元素。更多信息
关于那个错误,我看过这篇文章,它建议使用值(而不是输入 - 我这样做)并将所有初始值定义为一种类型。对我来说,它们都是字符串,尽管我尝试用空数组替换选择字段。在这两种选择中,控制台中都会返回相同的错误消息。
在这一点上 - 我不在乎我使用哪个自动完成或选择,我只想让其中一个工作。
有趣的是,在这两种情况下(使用选择和自动完成),控制台都会记录以下警告:
Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `one`, `two`.
(anonymous) @ 0.chunk.js:141301
0.chunk.js:141301 Material-UI: You have provided an out-of-range value `undefined` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are `a`, `b`, `c`, `d`.
但是,只有一个错误实例说:
A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: react-website -controlled-components
in input (created by ForwardRef(SelectInput))
in ForwardRef(SelectInput) (created by ForwardRef(InputBase))
in div (created by ForwardRef(InputBase))
in ForwardRef(InputBase) (created by WithStyles(ForwardRef(InputBase)))
in Wi
此错误指向类别选择表单输入。
我还尝试将此代码沙箱中的性别选择表单字段添加到我的表单中,以查看是否可以使其正常工作。当我注释掉上述类别和共享字段,并添加一个默认值为空字符串的性别字段时,表单会加载。
该字段是:
<Field
name="gender"
label="Gender"
options={[
{ value: "Male", label: "Male" },
{ value: "Female", label: "Female" },
{ value: "Other", label: "Other" }
]}
component={Select}
/>
出现性别选择字段,但宽度约为 1 厘米,选项菜单中未填充选项,我无法选择任何内容。但是表单确实会在性别字段中使用空字符串加载到 Firebase。这是进步,但还不足以向前迈进。
相同的代码沙箱显示了一个使用自动完成的字段。我尝试对其进行调整并以如下形式使用它:
<Field
name="gender"
label="Gender"
options={sharingOptions}
component={Autocomplete}
textFieldProps={{
label: sharingOptions.label
}}
/>
当我尝试这样做时,我收到一条错误消息:
TypeError:renderInput 不是函数
此错误消息对我来说毫无意义,因为我没有在表单中的任何地方使用 renderInput。
当我尝试:
<Box margin={1}>
<Field
component={Select}
type="text"
name="category"
label="Impact Category"
select
variant="outlined"
helperText="Select a category"
margin="normal"
style={{ width: "100%"}}
InputLabelProps={{
shrink: true,
}}
>
{allCategories.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Field>
</Box>
我没有收到任何错误,并且可以使用选项详细信息保存表单。但是,这实际上并不能解决自动完成为什么不起作用的问题。这也没有使用链接文档中显示的 Select 字段。所以我不清楚为什么这有效或为什么文档中显示的方法不起作用。
下一次尝试
使用此代码框中的自动完成示例作为指南,我尝试了:
<Field
name="autocomplete"
multiple
component={Autocomplete}
options={sharingOptions}
getOptionLabel={(option: any) => option.title}
style={{width: 300}}
renderInput={(params: AutocompleteRenderInputParams) => (
<MuiTextField
{...params}
error={touched['autocomplete'] && !!errors['autocomplete']}
helperText={touched['autocomplete'] && errors['autocomplete']}
label="Autocomplete"
variant="outlined"
/>
)}
/>
与前面的示例一样,我的代码编辑器在它出现在 getOptionLabel 中的值“any”下划线,它还强调 AutocompleteRenderInputParams。我找不到任何文档来解释表单字段的这些元素的含义或作用。无论如何,我已经导入了 AutocompleteRenderInputParams,如代码沙箱中所示。
我将表单中自动完成字段的初始值设为空数组 - 尽管我注意到代码沙箱在此示例中没有设置初始值。当我尝试删除自动完成的初始值时,我得到的错误与初始值为空数组时生成的错误相同,但我也在控制台中收到一条警告,上面写着:
警告:自动完成的值不是数组,这可能会导致意外行为
当我尝试此代码时,我的控制台会记录以下错误:
TypeError:无法读取未定义的属性“toLowerCase”
Material-UI:
getOptionLabel
自动完成的方法返回 undefined 而不是 {"value":"open","label":"Open"} 的字符串。