javascript 使用Formik验证时如何处理新用户?

omqzjyyz  于 2023-05-27  发布在  Java
关注(0)|答案(2)|浏览(91)

在我的react with typescript项目中,我使用Formik组件和Yup验证模式来验证地址表单。目前,它对现有用户工作得很好,因为initialValues填充了有效数据。此外,它还可以在用户输入时进行验证。现在,问题是对于一个新用户,其中initialValues为空,或者只有一些字段为空。因为窗体在初始化时验证空字段。我需要它不验证字段时,表单是一个新的使用初始化,但保持相同的行为验证字段的用户类型在它,并再次提交。
这是我到目前为止如何实现它的一个片段:
这是验证模式组件:

return Yup.object().shape({
    street: Yup.string()
      .required(messages.required)
      .test(
        'is-empty-or-whitespace',
        'This field can t be empty',
        (value) => value?.trim() !== ''
      ),
    city: Yup.string()
      .required(messages.required)
      .test(
        'is-empty-or-whitespace',
        'This field can t be empty',
        (value) => value?.trim() !== ''
      ),
      state: Yup.string()
      .required(messages.required)
      .test(
        'is-empty-or-whitespace',
        'This field can t be empty',
        (value) => value?.trim() !== ''
      ),
      zip: Yup.string()
      .required(messages.required)
      .test(
        'is-empty-or-whitespace',
        'This field can t be empty',
        (value) => value?.trim() !== ''
      )
this is how Formik is used in my parent component:
<Formik
          initialValues={{
            street: addressValues.street,
            city: addressValues.city,
            state: addressValues.state,
            country: addressValues.country,
          }}
          enableReinitialize={true}
          onSubmit={() => {
            submitHandler();
          }}
          validationSchema={validationSchema}
          valdateOnChange={true}
          validateOnBlur={true}
          validateOnMount={true}
        >
        {({ values, errors, handleChange, setFieldValue, setValues }) => (
            <Form id="addressForm">
              <Col className="someclass">
                <Row">
                  <MyInputFormControl
                    name="street"
                    type="text"
                    value={values.street}
                    placeholder=""
                    required={true}
                    disabled={false}
                    onChange={handleChange}
                    isInvalid={!!errors.street}
                    error={errors.street}
                    autoFocus
                  />
                </Row>
                <Row">
                  <MyInputFormControl
                    name="city"
                    type="text"
                    value={values.city}
                    placeholder=""
                    required={true}
                    disabled={false}
                    onChange={handleChange}
                    isInvalid={!!errors.city}
                    error={errors.city}
                  />
                </Row>
                <Row">
                  <MyInputFormControl
                    name="state"
                    type="text"
                    value={values.state}
                    placeholder=""
                    required={true}
                    disabled={false}
                    onChange={handleChange}
                    isInvalid={!!errors.state}
                    error={errors.state}
                  />
                </Row>
                <Row">
                  <MyInputFormControl
                    name="country"
                    type="text"
                    value={values.country}
                    placeholder=""
                    required={true}
                    disabled={false}
                    onChange={handleChange}
                    isInvalid={!!errors.country}
                    error={errors.country}
                  />
                </Row>
                </Form>
          )}
        </Formik>

到目前为止,我尝试设置validateOnMount={!isNewUser},将isNewUser传递给validationSchema,并像这样更改验证模式中的测试:

street: Yup.string()
      .required(messages.required)
      .test(
        'is-empty-or-whitespace',
        'This field can t be empty',
        (value) => {
           if (isNewUser) { return true; }
           return value?.trim() !== '';
      ),

但这根本不起作用。
有没有一种方法可以使用Formik和Yup来实现我想要的结果?

nx7onnlm

nx7onnlm1#

在Formik中,有一个touched的概念。这个想法是,你可以只显示错误,当有一个验证错误字段被 * 触摸 *(意味着用户已经与字段进行了任何有意义的交互)。
基本上,在你的代码中,你可以沿着这些行做一些事情:

{({ values, errors, handleChange, setFieldValue, setValues, touched }) => (

              ...

                  <MyInputFormControl
                    name="city"
                    type="text"
                    value={values.city}
                    placeholder=""
                    required={true}
                    disabled={false}
                    onChange={handleChange}
                    isInvalid={touched.city && !!errors.city}
                    error={touched.city ? errors.city : undefined}
                  />

                ...
               )}

根据您使用的输入组件库,有时您需要手动将字段标记为 touched,但在您的情况下,这似乎是不必要的,因为您使用的是来自Formik的handleChange。也许还值得添加onBlur={handleBlur}

eni9jsuy

eni9jsuy2#

您遇到的问题是由Formik组件的validateOnMount prop 引起的。当validateOnMount设置为true时,Formik会在表单初始化后立即对其进行验证。
在给定的用例中,您不希望表单验证最初为新用户触发,因此应该将validateOnMount设置为false。这应该可以解决问题。表单验证仍然会在用户输入和提交时触发,因为您已经将validateOnChange和validateOnBlur设置为true。
下面是代码的修改部分:

<Formik
  initialValues={{
    street: addressValues.street,
    city: addressValues.city,
    state: addressValues.state,
    country: addressValues.country,
  }}
  enableReinitialize={true}
  onSubmit={() => {
    submitHandler();
  }}
  validationSchema={validationSchema}
  validateOnChange={true}
  validateOnBlur={true}
  validateOnMount={false}  // Change this to false
>
  {({ values, errors, handleChange, setFieldValue, setValues }) => (
    // your form components
  )}
</Formik>

此更改确保表单在挂载时(即,当表单首次呈现时)不会进行验证,但在用户与表单交互时仍会进行验证。如果addressValues对象被更新(比如,当一个新用户登录时),表单将使用新值重新初始化,这要归功于enableReinitialize={true} prop,但它不会立即验证,因为validateOnMount是false。

相关问题