【问题标题】:Formik and Material-UIFormik 和 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 重大变化的影响。

标签: javascript reactjs typescript material-ui 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 的示例中所做的那样:

想法是一样的:实现自定义的“包装器”组件来包装 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>
          

          【讨论】:

            猜你喜欢
            • 2023-03-13
            • 2020-06-16
            • 1970-01-01
            • 2019-07-19
            • 2021-01-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-13
            相关资源
            最近更新 更多