问题
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.
回答1:
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
来源:https://stackoverflow.com/questions/57965523/useeffect-react-hook-rendering-multiple-times-with-async-await-submit-button