繁体   English   中英

如何在Formik提交验证之前清除状态?

[英]How to clear status before validation on Formik submit?

我正在使用带有 yup 验证的 Formik,遵循以下模式:

const handleSubmit = async (values, { setStatus }) => {
  setStatus(''); // clean errors messages
  try {
    ... do submit work ...
      const res = await sendData( convertValues(values)); //
    ... more work
  } catch (e) {
    console.error(e);
    setStatus('an error occurred '...);
  }
};

const validationSchema = Yup.object({
  code: Yup.string().required(t('Required')),
  ....
});

return (
    <Formik onSubmit={handleSubmit} initialValues={initialValues} validationSchema={validationSchema}>
      {({ setFieldValue, status }) => (
        <Form>
          ....
          <MyErrorComponent msg={status} />
        </Form>
      )}
    </Formik>
);

这在这种情况下有问题:

  1. 用户提交 forms。 验证通过,但在handleSubmit内部发生了一些错误。 状态中显示错误消息
  2. 用户编辑表单并重试
  3. 这次发生验证错误
  4. 验证错误显示在输入字段内......但旧的状态消息未清除。

发生这种情况是因为验证发生在提交之前,因此不调用setStatus('') 处理此问题的推荐方法是什么?

我认为你应该使用这样的东西:

<Formik
      initialValues={
        firstName: '',
        email: ''
      }
      validationSchema={
        Yup.object().shape({
          email: Yup.string()
            .email("Must be a valid email")
            .max(255)
            .required("Email is required"),
          firstname: Yup.string()
            .max(255)
            .required("First name is required"),
        })
      }
      onSubmit={(e, { resetForm }) => {
        let val = e;
        postSubmit (e.firstName,e.email);
        // ur rest logic
        // resetForm({
        //  values: {
        //    ...e,
        //  },
        });
      }}
    >
      {({ handleChange, values, initialValues, errors }) => (
        // Your form jsx
      )}
</Formik>

不要将useState与 formik 一起使用,让 Formik 处理错误和验证!

我确实使用了这种模式,并且效果很好。

如果您没有找到方法,请分享您的表格,以便为您制作!

它对 onMouseDown 事件有一个验证过程。 您可以通过防止提交按钮上的默认设置来避免重复验证。

 onMouseDown={(event: any): void => {
                event.preventDefault();
              }}

之后Formik自动清除状态

你可以为 formik 使用钩子useFormik

import { useFormik } from 'formik';
....
const formik = useFormik({
   initialValues: {},
   validationSchema={validationSchema}
   onSubmit: values => {
     handleSubmit(values);
   },
 });

const handleSubmit = async (values, { setStatus }) => {
  try {
    ... do submit work ...
    const res = await sendData( convertValues(values)); //
    ... more work
  } catch (e) {
    console.error(e);
    //change statuvalues or display errors
    //formik.setValue...
    //formik.setError...
  }
};

 
 return (
   <form onSubmit={formik.handleSubmit}>
     ....
     <button type="submit">Submit</button>
   </form>
 );

您可以通过更改的值来控制 Formik 何时运行验证

<Formik validateOnChange> and / or
<Formik validateOnBlur> props depending on your needs. 

默认情况下,Formik 将运行如下验证方法:

将道具传递给您的 Formik

validateOnChange={false} and 
validateOnBlur={false}

为了更好地理解检查文档Formik Validation

我个人认为状态只是为了通知用户。 所以我会通过告诉他们有错误从小吃店/通知中通知他们。 然后,如果验证表单上有错误,我会删除它们,以便他们专注于修复错误的表单

这是一个示例代码和沙箱


const validationSchema = yup.object().shape({
  name: yup.string().required("Required")
});

const initialValues = {
  name: "John Doe"
};

export const FormikTextField = ({ className, ...props }) => {
  const [field, meta] = useField(props);
  const { setStatus } = useFormikContext();

  useEffect(() => {
    if (meta.error) {
      setStatus("");
    }
  }, [meta.error]);

  return (
    <>
      <TextField
        variant="outlined"
        {...field}
        {...props}
        FormHelperTextProps={{ error: true }}
        helperText={meta.error && meta.touched ? String(meta.error) : null}
        aria-invalid={Boolean(meta.error)}
      />
    </>
  );
};

export default function App() {
  const handleSubmit = (values, { setStatus }) => {
    setStatus("status set!");
  };

  return (
    <Formik
      enableReinitialize
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={handleSubmit}
    >
      {(props) => (
        <Form>
          {props.status && <p>{props.status}</p>}
          <div className="App">
            <FormikTextField name="name" variant="outlined" label="Name" />
            <Button type="submit" variant="contained">
              Submit
            </Button>
          </div>
        </Form>
      )}
    </Formik>
  );
}

是的,你的假设是正确的。 提交前完成表单验证。 您需要做的是,在自定义验证 function 中添加此错误清除步骤

const validate = values =>
  {
   // If you want some other custom validations, you can do that on values parameter
   setStatus('');
  };

const handleSubmit = async (values, { setStatus }) => {
//  setStatus(''); // clean errors messages
  try {
    ... do submit work ...
      const res = await sendData( convertValues(values)); //
    ... more work
  } catch (e) {
    console.error(e);
    setStatus('an error occurred '...);
  }
};

const validationSchema = Yup.object({
  code: Yup.string().required(t('Required')),
  ....
});

return (
    <Formik onSubmit={handleSubmit} initialValues={initialValues} validationSchema={validationSchema}
validate={validate}>
      {({ setFieldValue, status }) => (
        <Form>
          ....
          <MyErrorComponent msg={status} />
        </Form>
      )}
    </Formik>
);

有关更多详细信息,请查看此CombinedValidations示例。

当您使用异步表单提交时,如async-submission所示。 您可能必须通过创建这样的包装器 Promise 来使用异步验证 function 或使您的表单提交同步。

以上示例的链接来自官方文档

选项1

您可以在每个表单输入中添加validate调用,以便用户更改输入status消息时将被清除。

import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";

const schema = Yup.object().shape({
  name: Yup.string().required("Name"),
  age: Yup.number().required("Number").positive().integer()
});

const MyForm = () => (
  <div>
    <Formik
      initialValues={{ name: "", age: "" }}
      validationSchema={schema}
      onSubmit={(values, actions) => {
        console.log("submited", values);
        actions.setStatus("")
        try {
          throw new Error("Something went wrong")
        }
        catch (error) {
          actions.setStatus(error.message);
        }
      }}
      render={({
        status,
        isSubmitting,
        setStatus,
        dirty,
        values,
        handleReset,
        errors,
        touched
      }) => {
        const field_props_with_validation = function() {
          const name = arguments[0];
          const type = arguments[1] || "text";
          const placeholder = arguments[2] || "";
          return {
            name,
            type,
            placeholder,
            validate: () => {
              setStatus("");
            }
          }
        }

        return (
          <Form>
            {status}
            {["name", "age"].map((field, key) => (
              <div key={key}>
                <Field {...field_props_with_validation(field)} />
                <ErrorMessage name={field} component="div" />
              </div>
            ))}
            <button type="submit">Enter</button>
          </Form>
        );
      }}
    />
  </div>
);

function App() {
  return (
    <div className="App">
      <h1>Registration Form</h1>
      <MyForm />
    </div>
  );
}

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

选项 2

可以使用validateOnChange道具在表单输入更改时disabled validation ,并且仅在用户提交表单时进行validate

注意:在这种情况下,您必须处理验证,在用户重新提交表单之前,状态不会被清除。

import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";

const schema = Yup.object().shape({
  name: Yup.string().required("Name"),
  age: Yup.number().required("Number").positive().integer()
});

const MyForm = () => (
  <div>
    <Formik
      initialValues={{ name: "", age: "" }}
      validateOnChange={false}
      onSubmit={async (values, actions) => {
        actions.setStatus("");
        await schema.validate(values, {
          abortEarly: false // not to stop on single validation fail
                            // and return single error message
        })
        .then(() => {
          try {
            throw new Error("Some error")
          }
          catch (error) {
            actions.setStatus(error.message);
          }
        })
        .catch(err => {
          let errors = {};
          Object.keys(values).forEach((key, idx) => {
            if (err && err.errors && err.errors[idx]) {
              errors[key] = err.errors[idx];
            }
          });

          actions.setErrors(errors)
        })
      }}
      render={({
        status,
        isSubmitting,
        dirty,
        values,
        handleReset,
        errors,
        touched
      }) => {
        return (
          <Form>
            {status}
            {["name", "age"].map((field, key) => (
              <div key={key}>
                <Field name={field} type="text" placeholder={field} />
                <ErrorMessage name={field} component="div" />
              </div>
            ))}
            <button type="submit">Enter</button>
          </Form>
        );
      }}
    />
  </div>
);

function App() {
  return (
    <div className="App">
      <h1>Registration Form</h1>
      <MyForm />
    </div>
  );
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM