Formik Material UI React - 自动完成 - 不受控制的状态

Mel*_*Mel 6 javascript reactjs material-ui formik formik-material-ui

我试图弄清楚如何按照此处的 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"
    />
  )}
/>;
Run Code Online (Sandbox Code Playgroud)

没有给出关于在 getOptionLabel 中使用 Movie 的含义的线索。当我尝试使用它时,电影和渲染输入对象中的 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);
Run Code Online (Sandbox Code Playgroud)

谁能看到如何根据上面链接中发布的文档使用 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>
Run Code Online (Sandbox Code Playgroud)

当我尝试这个时,我在控制台中收到一条警告:

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 ''
Run Code Online (Sandbox Code Playgroud)

此警告没有任何意义 - 表单呈现正确填充的菜单。

我也收到一条错误消息:

index.js:1 警告:组件正在将未定义类型的不受控制的输入更改为受控制。输入元素不应从不受控制切换到受控制(反之亦然)。决定在组件的生命周期内使用受控或非受控输入元素。更多信息

关于那个错误,我看过这篇文章,它建议使用值(而不是输入 - 我这样做)并将所有初始值定义为一个类型。对我来说,它们都是字符串,尽管我尝试用空数组替换选择字段。在这两种替代方案中,控制台中都会返回相同的错误消息。

在这一点上 - 我不在乎我使用哪个自动完成或选择,我只想让其中一个工作。

有趣的是,在这两种情况下(使用选择和自动完成),控制台都会记录警告说:

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`.
Run Code Online (Sandbox Code Playgroud)

但是,只有一个错误实例说:

 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
Run Code Online (Sandbox Code Playgroud)

此错误指向类别选择表单输入。

我还尝试将此代码沙箱中的性别选择表单字段添加到我的表单中,以查看是否可以使其正常工作。当我注释掉上述类别和共享字段,并添加一个默认值为空字符串的性别字段时,表单将加载。

该字段是:

<Field
                      name="gender"
                      label="Gender"
                      options={[
                        { value: "Male", label: "Male" },
                        { value: "Female", label: "Female" },
                        { value: "Other", label: "Other" }
                      ]}
                      component={Select}
                    />
Run Code Online (Sandbox Code Playgroud)

性别选择字段出现但大约 1 厘米宽,选项菜单没有填充选项,我无法选择任何内容。但是表单确实会在性别字段中使用空字符串加载到 firebase。这是进步,但还不足以继续前进。

相同的代码沙箱显示了一个使用自动完成的字段。我试图调整它并以我的形式使用它,如下所示:

<Field
                      name="gender"
                      label="Gender"
                      options={sharingOptions}
                      component={Autocomplete}
                      textFieldProps={{
                        label: sharingOptions.label
                      }}
                    />
Run Code Online (Sandbox Code Playgroud)

当我尝试这样做时,我收到一条错误消息:

类型错误: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>
Run Code Online (Sandbox Code Playgroud)

我没有收到任何错误,并且可以保存带有选项详细信息的表单。但是,这实际上并没有解决为什么自动完成不起作用的问题。这也不使用链接文档中所示的 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"
                />
              )}
            />
Run Code Online (Sandbox Code Playgroud)

与前面的示例一样,我的代码编辑器在 getOptionLabel 中出现的值“any”下划线,并且在 AutocompleteRenderInputParams 下划线。我找不到任何文档来解释表单字段的这些元素的含义或作用。无论如何,我已经导入了 AutocompleteRenderInputParams,如代码沙箱中所示。

我将表单中自动完成字段的初始值设置为一个空数组 - 尽管我注意到代码沙箱在此示例中没有设置初始值。当我尝试删除 autocomplete 的初始值时,我得到的错误与初始值为空数组时生成的错误相同,但我也在控制台中收到一条警告:

警告:自动完成的值不是数组,这可能会导致意外行为

当我尝试此代码时,我的控制台会记录以下错误:

类型错误:无法读取未定义的属性“toLowerCase”

Material-UI:getOptionLabel自动完成的方法返回 undefined 而不是字符串 {"value":"open","label":"Open "}。

Kuf*_*Kuf 4

工作示例:

演示

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

import { Formik, Field } from "formik";
import { Autocomplete } from "formik-material-ui-lab";
import { TextField } from "@material-ui/core";

const options = [
  { title: "The Shawshank Redemption", year: 1994 },
  { title: "Inglourious Basterds", year: 2009 },
  { title: "Snatch", year: 2000 },
  { title: "3 Idiots", year: 2009 },
  { title: "Monty Python and the Holy Grail", year: 1975 }
];

function App() {
  return (
    <Formik
      initialValues={{
        autocomplete: null
      }}
    >
      {() => (
        <Field
          name="autocomplete"
          component={Autocomplete}
          options={options}
          getOptionLabel={(option) => option.title}
          style={{ width: 300 }}
          renderInput={(params) => (
            <TextField {...params} label="Autocomplete" variant="outlined" />
          )}
        />
      )}
    </Formik>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Run Code Online (Sandbox Code Playgroud)