Source:  Twitter logo

I am trying to basically disable the submit button so my api calls only get triggered once/ someone can't click on submit again while the operation is already underway.

I converted the runOnSubmit function to an async function and call it directly. I have based this off many other solutions and basically when I do this and debug I can tell that isSubmitting is still set to true and the hook gets called multiple times/ the submitAsync function is called twice.

Basically, the setSubmitting gets called, but doesn't actually do anything until there is another refresh. I want it to only ever get called one time. I have no idea why submitAsync would even run multiple times since the dependencies (errors) are not changing. If they were changing then noErrors would be different the second time and it wouldn't even hit that block.

useEffect(() => {

        if (isSubmitting) {
            const noErrors = Object.keys(errors).length === 0;
            if (noErrors) {

                const submitAsync = async () => {
                    await runOnSubmit()
                    setSubmitting(false)
                }

                // clear out touched upon submission
                setTouched([]);
                submitAsync();
            } else {
                setSubmitting(false);
            }
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [errors]);

Update- adding in more information:

 // function for form submission
    const handleSubmit = (event) => {
        event.preventDefault();
        const validationErrors = validate(values);
        setErrors(validationErrors);
        setSubmitting(true);
    }

Since this function sets Submitting to true it should rerun the useEffect function since isSubmitting is in dependency array.

Button calling submit and disabling it:

<Button 
 disabled={isSubmitting} 
 buttonType="submit" 
 text="Create Account" />

My Button component:

<button 
  type={props.buttonType}
  disabled={props.disabled}
  onClick={props.onClick}>
     {props.text}
 </button>

SECOND EDIT- adding in console.logs:

useEffect(() => {
        console.log("use effect running", isSubmitting)
        if (isSubmitting) {
            console.log("use effect submitting true")
            const noErrors = Object.keys(errors).length === 0;
            if (noErrors) {
                console.log("use effect no errors")
                const submitAsync = async () => {
                    console.log("inside submit async")
                    await runOnSubmit()
                    console.log("after function")
                    setSubmitting(false)
                    console.log("after set false")
                }

                // clear out touched upon submission
                setTouched([]);
                submitAsync();
                console.log("console after submit")
            } else {
                setSubmitting(false);
            }
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isSubmitting === true]);

When running:

use effect running true
use effect submitting true
use effect no errors
inside submit async
the user called signup method
console after submit
after function
after set false
use effect running false

Issue here which doesn't make much sense is that "console after submit" runs before "after function". It's as if the async await isn't doing anything.

TO ANY NEW PERON HAVING THIS PROBLEM:

This second array argument passed to useEffect with data could be causing the multiple render. Pass in only an array [] and it will render once.

As stated here by react official site. The effect can be stopped if certain changes have not occurred between re-renders. This will prevent it from rendering multiple times

2 users liked answer #0dislike answer #02
Romeo profile pic
Romeo

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).