在 blur/change 和 'touched' 上分别显示 (1) 提交点击和 (2) 错误

Show errors both (1) on Submit click and (2) individually on blur/change with 'touched'

在 Formik 中,我需要在两种 情况下显示验证错误:

  1. 在 Change/Blur 上,当字段在表单上被触及时单独 -- 不是一次全部,在填写过程中
  2. 随时单击提交:此处,所有 错误应立即显示。

(1) 有效,但 (2) 无效。当我来到表单并单击“提交”按钮时,没有任何反应,也没有显示错误。只有在我触摸控件时才会显示错误。

我认为问题是为了满足(1),我的控件有

isInvalid={touched.startDate && errors.startDate}  

但是当我立即点击提交时,控件还没有被触及,所以这个isInvalid条件不成立。但我不能删除 touched.startDate 部分,否则, 所有 无效控件总是在填写表单时开始显示——即使是那些我没有接触过的控件。我需要在填写时保留我的 touched 要求,但还要在提交时显示所有错误。提交是必须立即显示所有错误的一种情况。是否可以在某处传递一些 submitClicked 变量来实现此目的?

<Formik enableReinitialize 
        validationSchema={schema}
        onSubmit={ (values, { validate }) => {
            alert(JSON.stringify(values, null, 2));
        }}
        initialValues={{}}
>
   {({
      handleSubmit,
      handleChange,
      handleBlur,
      values,
      touched,
      isValid,
      errors,
     }) => (
         <Form onSubmit={handleSubmit}> 
             ...
             {/* EXAMPLE */}
             <Form.Control type="date"
                           name="expirationDate"
                           value={values.expirationDate}
                           onChange={handleChange}
                           onBlur={handleBlur}
                           isInvalid={touched.expirationDate && errors.expirationDate}    
             </Form.Control>
         </Form>

...
// Yup Schema used for form validation
const schema = yup.object().shape({
    expirationDate: yup.date().required('Expiration Date is required'),
    frequencyDays: yup.number().required('Frequency is required'),
    interval: yup.string().required('Frequency interval is required'),
    ...           

我认为您是对的,因为您可以检查字段是否 touched,验证后不会呈现错误。我认为一个解决方法是在调用 onSubmit 处理程序后以编程方式将所有字段的状态设置为 touched=true

form.setTouched({...form.touched,[field.name]: true });

没有 codesandbox 可以使用,但类似这样的东西

<Formik enableReinitialize 
        validationSchema={schema}
        onSubmit={ (values, { validate }) => {
            // Set the form fields to touched programmatically
            form.setTouched({...form.touched,[field.name]: true });

            alert(JSON.stringify(values, null, 2));
        }}
        initialValues={{}}
>
   {({
      handleSubmit,
      handleChange,
      handleBlur,
      values,
      touched,
      isValid,
      errors,
     }) => (
         <Form onSubmit={handleSubmit}> 
             ...
             {/* EXAMPLE */}
             <Form.Control type="date"
                           name="expirationDate"
                           value={values.expirationDate}
                           onChange={handleChange}
                           onBlur={handleBlur}
                           isInvalid={touched.expirationDate && errors.expirationDate}    
             </Form.Control>
         </Form>

由于很多人都在查看此线程,因此我们得出了以下结果。这是我们的 React Bootstrap 控件示例,在本例中是一个在 Formik 中调用 frequencyDays 的 Select。请注意以下几点:

isInvalid={(submitClicked && errors.frequencyDays) || 
           (!submitClicked && touched.frequencyDays && errors.frequencyDays)}

这意味着 (1) 单击提交但存在错误,或者 (2) 未单击提交但触摸了此控件,但存在错误。

<Form.Control as="select"
    id="dropdownFrequencyDays"
    name="frequencyDays"
    value={values.frequencyDays}
    onChange={handleChange}
    onBlur={handleBlur}
    isInvalid={(submitClicked && errors.frequencyDays) || (!submitClicked && touched.frequencyDays && errors.frequencyDays)}

SubmitClicked是一个变量,initialized/set如下:

// Shows whether the Submit button was clicked (used to show all form validation errors at once)
// initially FALSE
const [submitClicked, setSubmitClicked] = useState(false);

在提交按钮的 onClick 中设置:

<Button type="submit" disabled={isSubmitting} 
   onClick={() => { 
       setSubmitClicked(true); // We set it to TRUE in Submit's onClick
            }} 
   variant="primary">Submit</Button>

如果您使用的是 Material UI,它与 React-Bootstrap 类似,它的控件上有一些 error 属性,类似于isInvalid.