【问题标题】:How to trigger validation in formik after rendering?渲染后如何在formik中触发验证?
【发布时间】:2019-10-08 21:18:14
【问题描述】:

我有一个关于 formik 的问题。基本上,我将有一个表格列出所有有错误的表格的 ID。当用户单击表单的 Id 时,它将显示表单本身。要求是在呈现表单时也应该显示错误。有谁知道如何用 Formik 做到这一点?此外,如果用户编辑字段,则字段验证应该正常工作。

我把代码框链接放在这里。 https://codesandbox.io/s/pensive-brattain-yyls2。基本上我希望当表单出现时我应该看到错误,而不仅仅是当用户离开该字段或更改它时。谢谢。

import { Formik, Field, Form } from "formik";
import { TextField } from "formik-material-ui";

class Post0 extends React.Component {
   validateEmptyName(value) {
      if (!value) {
        return "Invalid Name";
      }
   }

 render() {
  return (
  <div>
    <Formik
      initialValues={{
        email: "",
        animal: ""
      }}
      onSubmit={values => {
        this.props.nextStep(values);
      }}
      render={({ values, isSubmitting }) => (
        <Form>
          <Field
            name="email"
            type="email"
            value={values.email}
            component={TextField}
            variant="outlined"
            validate={this.validateEmptyName}
          />
          <Field
            name="animal"
            value={values.animal}
            component={TextField}
            variant="outlined"
          />

          <button type="submit">Submit</button>
        </Form>
      )}
    />
  </div>
);

} }

【问题讨论】:

  • 我能问一下您为什么要验证您知道将为空的表单吗?简单地指出该字段为必填项可能更有意义、更易于实施且更具视觉吸引力。
  • 嗨@RutherfordWonkington,很抱歉造成混乱,这只是一个例子。 initialStates 不能为空。例如,“电子邮件”=“”和“动物”=“猫”。但是当我显示表格时,我想看到那里显示的错误。这里的用例是有一个带有验证错误表单 ID 的表。当用户点击一个 ID 时,应该会显示带有验证错误的表单。谢谢
  • 啊。你现在的结构可能很难。 FormikProps 有一个validateForm 方法,但是在子渲染函数中调用它会触发一个无限循环。此外,由于您使用库组件作为接受 Formik 道具的输入,因此您需要确保字段将显示验证消息而无需先被触摸。

标签: reactjs formik


【解决方案1】:

我使用自定义输入组件制作了basic demo 版本。 Formik 没有内置选项来执行此操作,因此很遗憾,您需要创建自己的字段组件以与 Formik 的 props 集成,并绕过如果未触摸表单则不会显示验证的逻辑。

const Input = ({ field, form }) => {
  useEffect(() => {
    form.validateForm();
  }, []);

  return (
    <div>
      <input
        style={{
          border: form.errors[field.name] ? "1px solid red" : "1px solid #ccc"
        }}
        name={field.name}
        value={field.value}
        onChange={field.onChange}
      />
      {form.errors[field.name] && (
        <span style={{ color: "red" }}>{form.errors[field.name]}</span>
      )}
    </div>
  );
};

然后将其作为component 属性传递给您的&lt;Field/&gt;

Formik 确实提供了一个 isInitialValid 属性,您可以在主 Formik 组件上将其设置为 false,但同样,如果没有 touched 属性,您使用的库 TextFields 将不会显示任何内容。

【讨论】:

    【解决方案2】:

    2021 年更新:

    使用validateOnMount 道具:

    https://formik.org/docs/api/formik#validateonmount-boolean

    【讨论】:

    【解决方案3】:

    validateOnMount 如果您还添加了initialTouched,则可以使用,但是当它在提交后显示验证问题并不会导致不同的视图或组件时,它有限制(...或者更好的说法是错误)。

    我发现了非常优雅的解决方法,可以按预期工作。

    const formikRef = React.useRef(null);
    React.useEffect(() => formikRef.current.validateForm(), []);
    
    return (
        <Formik
            innerRef={formikRef}
            initialValues={props.customer}
            initialTouched={mapObject(props.customer, true)}
            onSubmit={values => {
    .
    .
    .
    

    【讨论】:

      【解决方案4】:

      我使用 Yup 的 validateAtSync function 完成了此操作,同时从查询字符串填充表单的初始值。

      function generateInitialValues(tabs: TabType[], router: any, validationSchema: any) {
        const initialValues: { [key: string]: number | string }  = {};
        _.forEach(tabs, (tab: TabType) => {
          _.forEach(tab.formFields, (f: FormField) => {
            let isFieldValid;
            try {
              // https://github.com/jquense/yup#mixedvalidatesyncatpath-string-value-any-options-object-any
              console.log('validation schema validateAt: ', validationSchema.validateSyncAt(f.id, router.query[f.id]));
              isFieldValid = validationSchema.validateSyncAt(f.id, router.query[f.id]);
            } catch (e) {
              // do nothing on purpose to stop exception from being thrown
              // TODO: Consider doing something here, such as recording a metric
            }
      
            initialValues[f.id] = isFieldValid ? router.query[f.id] : f.defaultValue;
          })
        });
        return initialValues;
      }

      【讨论】:

        【解决方案5】:

        您可以使用 isInitialValid 或 initialErrors 来使初始值有效。 查看他们的官方文档here

        【讨论】:

          猜你喜欢
          • 2021-12-23
          • 1970-01-01
          • 1970-01-01
          • 2019-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-29
          • 2021-05-01
          相关资源
          最近更新 更多