簡體   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