将 Material-UI 的 Autocomplete 组件与 Formik 一起使用

Posted

技术标签:

【中文标题】将 Material-UI 的 Autocomplete 组件与 Formik 一起使用【英文标题】:Using Material-UI's Autocomplete component with Formik 【发布时间】:2020-03-31 17:07:44 【问题描述】:

目前正在尝试将 Material UI 的 Autocomplete 组件与 Formik 一起使用。到目前为止,诸如文本字段和 Material-UI 中的传统选择之类的东西在 Formik 上表现得非常好。实现自动完成并非如此。 Formik 的 onChange 处理程序似乎没有更新我的 city_id 的值。我知道 Autocomplete 仍然不是 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);

【问题讨论】:

【参考方案1】:

您的问题是 handleChange 无法按照您的方式工作。

如果你看看handleChange docs:

一般输入更改事件处理程序。这将更新 values[key] ,其中 key 是事件发射输入的名称属性。如果 name 属性不存在,handleChange 将查找输入的 id 属性。注意:这里的“输入”是指所有 html 输入。

这应该可以正常工作,但问题是Autocomplete中的TextField只会在您在其上键入内容时触发handleChange,并且值将是文本,而不是id或其他属性你想要,所以你需要将handleChange移动到Autocomplete

还有一个问题,你不能在Autocomplete中使用handleChange,因为它没有引用你想要的输入,而且它也有不同于input的普通onChange的参数,正如您在docs 中看到的那样。

onChange 功能 值更改时触发回调。 签名:function(event: object, value: any) =&gt; voidevent:回调的事件源value:null

所以你需要做的是使用setFieldValue 并将其传递给Autocomplete 就像

onChange=(e, value) => setFieldValue("city_id", value)

您需要传递您的字段名称以及您想要获取的值。

这是working example

【讨论】:

完美!谢谢! @CarlEdwards 欢迎您,请考虑投票,谢谢! 完整解释完毕! 如果我的问题被认为值得注意,请考虑支持我的问题。 另外,材料 4.7.1 中的自动完成组件上有 8 个补丁,所以如果有人在遵循 Vencovsky 的解释后仍有问题,这可能就是原因。【参考方案2】:

@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 元素时,它会触发onOpen,它运行Formik onBlur 并将该字段标记为已触摸。如果一个项目没有被拾取,Formikflags 字段并显示Contact is required 验证消息。

【讨论】:

onOpen=handleBlur 在选择期间显示“必需”错误。改用onBlur=handleBlur 会更好,因为只有在选择/清除后才会显示错误。【参考方案3】:

你必须在Autocomplete标签中添加onChange = (event, value) =&gt; 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 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

React & Material-UI 分页 - 将 Material-UI 的组件连接到 React-Router

Material-ui <Autocomplete /> getOptionLabel - 将空字符串作为值传递

material-ui 组件样式自定义 - 将选择组件的颜色更改为白色

Material-UI 滑块未将名称道具暴露给 Formik

将 Material-UI 的 Autocomplete 组件与 Formik 一起使用

Material-UI:如何将 Drawer 组件置于 AppBar 下方