简体   繁体   English

如何在 React Final Form 中提交时重新运行验证

[英]How to rerun validation on submit in React Final Form

Once a form's fields have been validated, submitting doesn't trigger a rerun of the validation.一旦表单的字段被验证,提交不会触发重新运行验证。 Is there a way I can trigger a rerun of the validation when the form is submitted?有没有办法在提交表单时触发重新运行验证?

I have a form field whose value can become invalid if it's not submitted within a particular timeframe.我有一个表单字段,如果未在特定时间范围内提交,其值可能会变为无效。 It's not async;这不是异步的; I'm just trying to cover a scenario in which the user doesn't click submit for a while, and when they eventually do, the value would have become invalid.我只是想介绍一个场景,在这种情况下,用户有一段时间没有点击提交,当他们最终点击提交时,该值将变得无效。 Final form remembers the result of the validation that happens immediately after the value is changed, which means that the unchanged value remains valid regardless of how much time passes between the validation and the submission.最终表单会记住值更改后立即发生的验证结果,这意味着无论验证和提交之间经过多长时间,未更改的值仍然有效。 This is the behavior I want to hook into and change;这是我想要挂钩和改变的行为; the intervening time matters in my use case.在我的用例中,中间时间很重要。 I have tried using the beforeSubmit listener from the final-form-submit-listener package but it only gives access to the FormApi object.我尝试使用final-form-submit-listener包中的beforeSubmit侦听器,但它只提供对FormApi对象的访问权限。 I tried using the pauseValidation and resumeValidation functions from FormApi but they couldn't achieve what I want, or maybe I'm not using them correctly.我尝试使用pauseValidationresumeValidation从功能FormApi但他们无法达到我想要的东西,或者也许我没有正确地使用它们。 I have a feeling it's painfully obvious how to do this, but I can't figure it out.我有一种感觉,如何做到这一点非常明显,但我无法弄清楚。 😩 😩

I created this Sandbox to demonstrate what I mean.我创建了这个沙箱来演示我的意思。

Thanks!谢谢!

UPDATE : Some additional information:更新:一些附加信息:

  • This is for a time picker.这是一个时间选择器。 If you're picking times for today, you may pick a time that is 15 minutes from now.如果您选择今天的时间,您可以选择从现在起 15 分钟后的时间。 It's valid now because it's currently in the future.它现在有效,因为它现在是未来。 If you don't touch the form for the next 20 minutes then click submit, the submission should be prevented because your selected time is now 5 minutes in the past.如果您在接下来的 20 分钟内没有触摸表单然后单击提交,则应阻止提交,因为您选择的时间现在是过去 5 分钟。
  • I have considered just adding the validation directly in the submit handler.我考虑过直接在提交处理程序中添加验证。 Two answers here do this.这里有两个答案可以做到这一点。 However, it is not ideal for me because Final Form doesn't receive the errors and pass them to the meta object for the form fields.但是,它对我来说并不理想,因为 Final Form 不会收到错误并将它们传递给表单字段的meta对象。 My codebase is complex and relies heavily upon the meta object to display error messages.我的代码库很复杂并且严重依赖于meta对象来显示错误消息。 Trying to replicate that functionality in the submit handler may work but it's hacky and goes against the convention used throughout the codebase.尝试在提交处理程序中复制该功能可能会起作用,但它很笨拙,并且违反了整个代码库中使用的约定。

Library author here.图书馆作者在这里。 I'm always fascinated by new ways people can invalidate my assumptions.我总是对人们可以使我的假设无效的新方法着迷。 I mean that in a sincerely positive way, as it results in learning.我的意思是以一种真诚积极的方式,因为它会导致学习。

🏁 Final Form makes the assumption that your validation functions are "pure" or "idempotent" , ie will always return the same result when given the same values. 🏁 Final Form 假设您的验证函数是“纯”或“幂等的” ,即当给定相同的值时将始终返回相同的结果。 This is why it doesn't run the synchronous validation again (just to double check) before allowing the submission: because it's already stored the results of the last time it ran it.这就是为什么在允许提交之前它不会再次运行同步验证(只是为了仔细检查):因为它已经存储了上次运行它的结果。 By using an outside timer, you've invalidated that assumption.通过使用外部计时器,您已经使该假设无效。

If you have a better/simpler/"more official" solution, I'd still love to see it!如果您有更好/更简单/“更官方”的解决方案,我仍然很乐意看到它!

No need for mutators or decorators for this problem.这个问题不需要修改器或装饰器。

The more official way to do this would be to run the check (you could even reuse this.validate ) in onSubmit .更正式的方法是在onSubmit运行检查(您甚至可以重用this.validate )。 The only tricky part is that the error will come back as meta.submitError , so you need to check for both when displaying your error.唯一棘手的部分是错误将作为meta.submitError ,因此您需要在显示错误时检查两者 Like so:像这样:

编辑提交时强制重新验证(React Final Form)

You're already putting a function inside onSubmit , why not just add the functionality you want to it?您已经在onSubmit放置了一个函数,为什么不添加您想要的功能呢? event.preventDefault() and then work with your validate function, it' sa part of the component and accessible to you. event.preventDefault()然后使用您的验证功能,它是组件的一部分,您可以访问。

handleOnSubmit(e){
  let value = document.querySelector("input").value 
  if (!!this.validate(value)){
    e.preventDefault();
    alert("Prevented submit event")
  } else{
    alert("Form submitted")
  }
}

now just use this function in the form onSubmit prop(I put in bot since i wasn't sure about the component structure):现在只需以onSubmit prop 的形式使用此函数(我放入了 bot,因为我不确定组件结构):

<Form onSubmit={this.handleOnSubmit}>...</Form>
<form onSubmit={this.handleOnSubmit}>

And remove the submitListener decorator from the Form component:并从 Form 组件中移除submitListener 装饰器:

decortaor={submitListener}

Now it will check the validation before submitting and prevent it if not validated.现在它将在提交之前检查验证,如果未验证则阻止它。

So I have found a way to do this!所以我找到了一种方法来做到这一点! 🎉 I use a mutator and use it's changeValue function to 'change' the value of the relevant field (I supply the same value). 🎉 我使用了一个mutator并使用它的changeValue函数来“更改”相关字段的值(我提供相同的值)。 This in turn notifies all relevant parties of the change to the form's state, and a validation is triggered.这反过来通知所有相关方表单状态的更改,并触发验证。 The key is to call the mutator inside the submit handler, which therefore ensures that the validation is performed when the form is submitted.关键是在提交处理程序中调用 mutator,从而确保在提交表单时执行验证。 Have a look at this new Sandbox .看看这个新的沙箱

The relevant bits are as follows:相关位如下:

// this is a stateful component
...
...
  mutateValue([name], state, { changeValue }) {
    // change the value to the same value, thus
    // triggering a revalidation of the same value
    changeValue(state, name, value => value);
  }

  handleSubmit(values) {
    alert("submitted");
  }

  render() {
    return (
  ...
  ...
        <Form
          onSubmit={this.handleSubmit}
          mutators={{ mutateValue: this.mutateValue }}
          render={({
            handleSubmit,
            form: {
              mutators: { mutateValue }
            }
          }) => {
            const mutateBeforeSubmit = values => {
              // supply the name of the relevant form field
              mutateValue("revalidate");
              // submit handler gets called if revalidation still passes
              handleSubmit(values);
            };
            return (
              <form onSubmit={mutateBeforeSubmit}>
              ...
              ...
              </form>
            );
          }}
        />
        ...
        ...

And because it's triggering the same validation mechanism, meta gets used accordingly!并且因为它触发了相同的验证机制,所以meta被相应地使用!

If you have a better/simpler/"more official" solution, I'd still love to see it!如果您有更好/更简单/“更官方”的解决方案,我仍然很乐意看到它!

Since you want to enforce re-validation OR stop submission of form based on the interval , why not use disabled on submit button?既然您想根据时间interval强制重新验证或停止提交表单,为什么不在提交按钮上使用disabled

// interval less than 900 = 15 minutes
<button type="submit" disabled={this.state.interval>=900}>
    Submit
</button>

I have also read docs of react-final-form but I thinks it's more easy unless you have a specific case to address using meta .我也阅读了react-final-form文档,但我认为它更容易,除非你有一个特定的案例需要使用meta来解决。

Got another use case where manual triggering validation is needed: In this case we got an student form, in case we got a new student, a field called temporary password must be fullfilled, if not that field is not mandatory, to keep it simple we update the validation schema on the fly (we had a similar case with a validation that needs to be included whenever some fetch operation was completed).有另一个需要手动触发验证的用例:在这种情况下,我们有一个学生表格,如果我们有一个新学生,必须填写一个名为临时密码的字段,如果不是,该字段不是强制性的,为了简单起见,我们动态更新验证模式(我们有一个类似的案例,需要在完成某些提取操作时包含验证)。

We applied @uche-ozoemena and it worked fine, but @erik-r is this solution considered a hack or is something that we can use as an approved workaround in scenarios where we need to manually trigger validations?我们应用了@uche-ozoemena 并且它工作正常,但是@erik-r 这个解决方案是否被认为是一种黑客行为,或者我们可以在需要手动触发验证的场景中将其用作已批准的解决方法?

We got something like (using fonk-final-form):我们得到了类似的东西(使用 fonk-final-form):

  React.useEffect(() => {
    if (isUserCreation) {
      const newDataFormvalidationSchema = {
        ...dataFormvalidationSchema,
        field: {
          ...dataFormvalidationSchema.field,
          temporaryInitialPassword: [
            ...dataFormvalidationSchema.field.temporaryInitialPassword,
            Validators.required,
          ],
        },
      };

      dataFormValidation.updateValidationSchema(newDataFormvalidationSchema);
    }
  }, [isUserCreation]);

  return (
    <Form
      initialValues={initialData}
      mutators={{ mutateValue: mutateValue }}
      onSubmit={values => {
        save(values);
      }}
      validate={dataFormValidation.validateForm}

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

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