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

How to rerun validation on submit in React Final Form

验证表单的字段后,提交不会触发重新运行验证。有什么方法可以在提交表单时触发重新运行验证?

我有一个表单字段,如果未在特定时间范围内提交,其值可能会失效。这不是异步的;我只是想涵盖用户有一段时间没有点击提交,而当他们最终点击提交时,该值将变得无效的场景。最终表单会记住值更改后立即发生的验证结果,这意味着无论验证和提交之间经过多长时间,未更改的值仍然有效。这是我想要挂钩并改变的行为;在我的用例中,干预时间很重要。我尝试使用 final-form-submit-listener 包中的 beforeSubmit 侦听器,但它只允许访问 FormApi 对象。我尝试使用 FormApi 中的 pauseValidationresumeValidation 函数,但它们无法实现我想要的,或者我没有正确使用它们。我有一种感觉,如何做到这一点很明显,但我想不通。

我创建 this Sandbox 来证明我的意思。

谢谢!

更新:一些附加信息:

您已经在 onSubmit 中添加了一个函数,为什么不直接添加您想要的功能呢? event.preventDefault() 然后使用您的验证函数,它是组件的一部分,您可以访问。

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

现在只需以 onSubmit prop 的形式使用此功能(我放入 bot 因为我不确定组件结构):

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

并且从表单组件中删除 submitListener 装饰器:

decortaor={submitListener}

现在它会在提交前检查验证,如果没有验证则阻止它。

既然你想强制re-validation或停止提交基于interval的表单,为什么不在提交按钮上使用disabled

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

我也阅读了 react-final-form 的文档,但我认为它更容易,除非你有一个特定的案例需要使用 meta

所以我找到了一个方法来做到这一点! 我使用 mutator and use it's changeValue function to 'change' the value of the relevant field (I supply the same value). 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. Have a look at this new Sandbox.

相关位如下:

// 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>
            );
          }}
        />
        ...
        ...

并且由于它触发了相同的验证机制,因此 meta 得到了相应的使用!

如果您有 better/simpler/"more official" 解决方案,我仍然很乐意看到它!

这里是图书馆作者。我总是对人们可以使我的假设无效的新方法着迷。我的意思是以真诚积极的方式,因为它会带来学习。

Final Form 假设您的验证函数是 "pure" 或 "idempotent",即给出的结果总是 return 相同相同的值。这就是为什么它在允许提交之前没有再次 运行 同步验证(只是为了仔细检查):因为它已经存储了上次它 运行 的结果。通过使用外部计时器,您已经使该假设无效。

If you have a better/simpler/"more official" solution, I'd still love to see it!

这个问题不需要修改器或装饰器。

更正式的方法是 运行 在 onSubmit 中检查(您甚至可以重复使用 this.validate)。唯一棘手的部分是错误将返回为 meta.submitError,因此您需要在显示错误时检查 both。像这样:

得到另一个需要手动触发验证的用例:在这种情况下,我们有一个学生表格,如果我们有一个新学生,一个名为 临时密码 的字段必须是fullfilled,如果不是该字段不是强制性的,为了简单起见,我们即时更新验证模式(我们有一个类似的情况,每当完成某些提取操作时都需要包含验证)。

我们应用了@uche-ozoemena 并且运行良好,但是@erik-r 这个解决方案是否被认为是 hack 或者我们可以在需要手动触发验证的情况下用作批准的解决方法?

我们得到了类似的东西(使用 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}