jaredpalmer / formik

Build forms in React, without the tears đŸ˜­
https://formik.org
Apache License 2.0
34.01k stars 2.79k forks source link

Make onSubmit not invoke the callback if submission is already ongoing #3265

Open emilmuller opened 3 years ago

emilmuller commented 3 years ago

If onSubmit returns a Promise, onSubmit should not invoke the callback again until the Promise resolves or rejects.

Right now, when onSubmit gets invoked, there is no way of knowing if the submission is already ongoing because Formik sets isSubmitting to true before invoking the callback.

A solution is to disable all the buttons with the submit type.

However (I might be wrong though), I can't find anything in the W3 specification that says if a form cannot be submitted if it's submit button is disabled. It seems to be chrome's behaviour. Unsure about other browsers.

johnrom commented 3 years ago

@emilmuller that is actually the recommended way to do this, though there have been concerns about its accessibility. The W3 text you are looking for is here:

https://www.w3.org/TR/html52/sec-forms.html#implicit-submission

A form element’s default button is the first Submit Button in tree order whose form owner is that form element.

If the user agent supports letting the user submit a form implicitly (for example, on some platforms hitting the "enter" key while a text field is focused implicitly submits the form), then doing so for a form whose default button has a defined activation behavior must cause the user agent to run synthetic click activation steps on that default button.

Consequently, if the default button is disabled, the form is not submitted when such an implicit submission mechanism is used. (A button has no activation behavior when disabled.)

Note that this does not block explicit submission, that is -- you could submit the form by calling document.querySelector("form").submit(). However, the only way W3 defines submission via HTML5 is via the Submit button, and implicitly activating that button via the concept of a default button.

If you want a workaround, you can always fall back to your own disabled state, like:


const MyForm = () => {
  // use a Ref and not State, because onSubmit isn't part of React's component lifecycle
  const isDisabledRef = React.useRef(false);

  return <Formik 
    {...otherProps}
    onSubmit={(values) => {
      if (!isDisabledRef.current) {
        isDisabledRef.current = false;
        try {
           // your submission logic
        } finally {
          isDisabledRef.current = true;
        }
      }
    }
  />
}
emilmuller commented 3 years ago

Thanks for your thorough response! I am in error, and agree with the current implementation :)

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days