【发布时间】:2020-01-17 19:16:15
【问题描述】:
我试图基本上禁用提交按钮,这样我的 api 调用只会触发一次/在操作正在进行时有人不能再次点击提交。
我将 runOnSubmit 函数转换为异步函数并直接调用它。我已经基于许多其他解决方案,基本上当我这样做和调试时,我可以说 isSubmitting 仍然设置为 true 并且钩子被多次调用/ submitAsync 函数被调用两次。
基本上,setSubmitting 会被调用,但实际上在再次刷新之前不会执行任何操作。我希望它只被调用一次。我不知道为什么 submitAsync 甚至会运行多次,因为依赖项(错误)没有改变。如果它们发生变化,那么 noErrors 第二次会有所不同,甚至不会命中该块。
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]);
更新-添加更多信息:
// function for form submission
const handleSubmit = (event) => {
event.preventDefault();
const validationErrors = validate(values);
setErrors(validationErrors);
setSubmitting(true);
}
由于这个函数将 Submitting 设置为 true,它应该重新运行 useEffect 函数,因为 isSubmitting 在依赖数组中。
按钮调用提交并禁用它:
<Button
disabled={isSubmitting}
buttonType="submit"
text="Create Account" />
我的按钮组件:
<button
type={props.buttonType}
disabled={props.disabled}
onClick={props.onClick}>
{props.text}
</button>
第二次编辑-在 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]);
运行时:
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
这里没有多大意义的问题是“提交后的控制台”在“函数后”之前运行。就好像异步等待没有做任何事情。
【问题讨论】:
-
似乎提供的代码不足以重现您的问题。
[errors]作为useEffect钩子的第二个参数可能会导致它过时并且在errors对象更改之前不会重新运行。但这取决于您如何声明和修改errors。或者useEffect可能在每次渲染后被调用,这主要取决于isSubmitting是如何改变的 -
我实际上认为你是对的,不知道为什么我什至在那里使用错误。我将依赖数组更改为
[isSubmitting === true],因为我希望它仅在提交时重新运行。问题是我可以连续点击提交并且它没有被禁用。在上面添加handleSubmit函数和提交按钮 -
我将您的代码放在代码沙箱中,无法重现您的问题。 codesandbox.io/s/useeffect-called-twice-0ybcy
-
这太奇怪了。我会尝试放置完整的代码,但它使用了我们所有的后端 api,所以很难复制。我在 console.logs 中添加了,很明显它没有等待响应。也许我需要尝试使用 Promise,但我已经尝试过 .then().catch() 等差异
-
@StephenPhillips 如果我们看不到
errors的来源以及它是如何声明和修改的,那么将很难帮助解决您的问题。也不清楚为什么isSubmitting不在您的依赖数组中,因为您在回调正文中引用了它。
标签: javascript reactjs async-await use-effect