Formik 和 Material-UI

Posted

技术标签:

【中文标题】Formik 和 Material-UI【英文标题】:Formik and Material-UI 【发布时间】:2019-02-06 05:59:48 【问题描述】:

我正在尝试将 Formik 与 Material-UI 文本字段一起使用。像这样:

import TextField from '@material-ui/core/TextField';
import 
  Field,
  FieldProps,
  Form,
  Formik,
  FormikErrors,
  FormikProps
 from 'formik';
import React,  Component  from 'react';

interface IMyFormValues 
  firstName: string;


class CreateAgreementForm extends Component<> 
  public render() 
    return (
      <div>
        <h1>My Example</h1>
        <Formik
          initialValues= firstName: '' 
          // tslint:disable-next-line:jsx-no-lambda
          onSubmit=(values: IMyFormValues) => alert(JSON.stringify(values))
          // tslint:disable-next-line:jsx-no-lambda
          validate=(values: IMyFormValues) => 
            const errors: FormikErrors<IMyFormValues> = ;
            if (!values.firstName) 
              errors.firstName = 'Required';
            
            return errors;
          
          // tslint:disable-next-line:jsx-no-lambda
          render=(formikBag: FormikProps<IMyFormValues>) => (
            <Form>
              <Field
                name="firstName"
                render=( field, form : FieldProps<IMyFormValues>) => (
                  <TextField
                    error=Boolean(
                      form.errors.firstName && form.touched.firstName
                    )
                    helperText=
                      form.errors.firstName &&
                      form.touched.firstName &&
                      String(form.errors.firstName)
                    
                  />
                )
              />
            </Form>
          )
        />
      </div>
    );
  


export default CreateAgreementForm;

我希望 Formik 负责外观的验证和 Material-UI。 我想将 errors.firstName 传递给 TextField 组件,但错误显示不正确。我怎样才能修复它,这样它仍然可以清楚地阅读?我不想编写自己的 TextField 组件。

【问题讨论】:

我不知道如何将 Material-ui 组件与 Formik 验证集成,但我可以推荐 react-final-form ,它与 MUI 集成得很好:github.com/final-form/react-final-form#material-ui-10 谢谢,但我仍然需要为每个 material-ui 组件创建自定义组件。我宁愿不要。你知道怎么做吗? 这看起来有点矫枉过正,但我​​们发现像这样包装 material-ui 表单组件实际上很简单直接。我认为您总是必须以某种方式将“FormXXX”框架道具映射到 Material-UI 组件。 你可以看看这个项目做了什么:github.com/stackworx/formik-material-ui/tree/master/src 我真的认为您应该考虑为每个 Material-UI 组件创建自定义组件。原因如下:不要重复自己(Formik API 到 MUI props 的映射是一次性完成的),限制未来 MUI 或 Formik 重大变化的影响。 【参考方案1】:

我认为您不需要另一个库,甚至不需要创建自己的包装器,我认为您需要稍微调整一下代码。

您遇到的一个问题是您没有在 Material TextField 中传递 onChange 函数,因此 firstName 的表单值始终为空,因此即使您输入了名称,您也总是会收到错误消息。 尝试在 TextField 和 onChange 函数上添加名称或 ID,如下所示:

<Field
    validateOnBlur
    validateOnChange
    name="firstName"
    render=( field, form ) => (
    <TextField
        name="firstName"
        error=
            Boolean(form.errors.firstName && form.touched.firstName)
        
        onChange=formikBag.handleChange
        onBlur=formikBag.handleBlur
        helperText=
            form.errors.firstName &&
            form.touched.firstName &&
            String(form.errors.firstName)
        
    />
    )
/>

【讨论】:

不行,还是不行。字段为空时不显示错误 出现错误,但目前您已将验证设置为在提交时显示。这意味着您需要按回车键才能显示它。如果您希望它们也出现 onChange 和 onBlur ,请参阅我更新的答案。希望这会有所帮助。 您会发现自己在每个“字段”实例中重复将道具映射到 Material-UI 组件道具,这就是为我创建 Material-UI 包装器的重点,集中此映射确实有意义在自定义组件中。想象有一天,MUI 或 Formik 的 API/Props 发生了重大变化。您只需要更新一个组件! 你说得对,包装组件是个好主意。但我认为在这里要做的第一件事是让它在单个领域工作,然后他可以专注于根据他需要构建的内容构建包装器。 这是要去的地方formik.org/docs/api/field#children【参考方案2】:

正如 cmets 中提到的,实现“包装”组件实际上可能是一个好主意,就像他们在 Formik 或 ReactFinalForm 的示例中所做的那样:

https://github.com/stackworx/formik-material-ui/tree/master/src https://github.com/final-form/react-final-form#material-ui-10

想法是一样的:实现自定义的“包装器”组件来包装 Material-UI 组件并映射 Formik 或 ReactFinalForm APIs props。

这种方法的优点是将两个框架之间的映射集中在一个地方,这样您就不必每次都重复映射,如果其中一个框架引入了重大更改,您只需更改那些自定义的“包装器” " 组件。

【讨论】:

【参考方案3】:

你可以试试这个:https://github.com/daixianceng/formik-material-fields

安装:

npm install --save formik-material-fields

用法:

import React,  Component  from 'react';
import  Formik, Form  from 'formik';
import * as Yup from 'yup';
import  FormikTextField  from 'formik-material-fields';

const validationSchema = Yup.object().shape(
  username: Yup.string().required(),
);

const initialValues = 
  username: '',
;

class MyForm extends Component 
  render() 
    return (
      <Formik
        initialValues=initialValues
        validationSchema=validationSchema
        onSubmit=this.props.onSubmit
      >
        ( isValid ) => (
          <Form autoComplete="off">
            <FormikTextField
              name="username"
              label="Username"
              margin="normal"
              fullWidth
            />
          </Form>
        )
      </Formik>
    );
  

【讨论】:

很好的答案!谢谢 对于需要快速简单 UI 的后端人员来说,这个库太棒了!【参考方案4】:

您也可以试试这个库,它为您完成了繁重的工作并实现了 Material-UI 组件周围的包装代码(包括 &lt;TextField /&gt;):https://github.com/stackworx/formik-material-ui。

安装:

yarn add formik-material-ui

在您的 Formik 表单组件中,将 &lt;TextField /&gt; 组件作为 Formik &lt;Field /&gt; 组件的组件属性传递。

import  Formik, Field, Form  from 'formik';
import  TextField  from 'formik-material-ui';

<Field
  name="email"
  label="Email"
  type="email"
  component=TextField
/>

Formik 将继续按预期处理验证,并将呈现 Material UI 组件和错误消息。其他 Mui 输入组件的文档中有更多详细信息,并有助于自定义。

【讨论】:

【参考方案5】:

在此处查看 &lt;Field /&gt; 的 formik 文档:https://jaredpalmer.com/formik/docs/api/field

例如,您可以使用 Material 的 OutlinedInput 设置输入样式:

<Field as=OutlinedInput />

【讨论】:

【参考方案6】:

要使用 ma​​terial-uiformik,您可以使用 formik 官方文档中的变体: https://formik.org/docs/examples/with-material-ui

【讨论】:

【参考方案7】:

您可以使用setFieldValue 方法可用于创建自定义输入更改处理程序

<Formik
  initialValues=
    name: "",
  
  onSubmit=(values: any) => console.log(values)
>
  (  handleSubmit, setFieldValue ) => (
    <Form noValidate autoComplete="off" onSubmit=handleSubmit>
      <TextField
        onChange=(event) => setFieldValue("name", event.target.value) 
        type="text"
        label="Name"
      />
    </Form>
  )
</Formik>

【讨论】:

以上是关于Formik 和 Material-UI的主要内容,如果未能解决你的问题,请参考以下文章

使用 Formik 和 Yup 和 React-select 进行验证

Formik:useField 钩子上的 onBlur 处理程序

如何在 react-apollo-hooks 和 formik 中使用突变?

使用 Yup 和 Formik 自动修剪空白

如何默认 formik 日期和时间字段以显示占位符值

React Formik:如何使用自定义 onChange 和 onBlur