我有一个函数 runValidation,它循环遍历一堆数字并进行一些计算。这可能需要一段时间,所以我想包含一个“isLoading”useState。
所以我做了一个简单的
const [isLoading, setIsLoading] = useState(false)
当我单击一个按钮时,我想将 isLoading 设置为 true,运行我的函数,然后执行 setIsLoading(false)。 所以我让我的验证函数异步,以及按钮处理程序
const handleClick = async () => {
setIsLoading(true)
const isValid = await runValidation()
setIsLoading(false)
}
我的按钮组件很简单
<button onClick={() => handleClick()}>Run Validations</button>
然而,每次我尝试运行它时,在验证功能完成之前都没有设置加载。所以在“isLoading”变量上有一个 useEffect 。我得到 console.logs 显示
Running Validations
isLoading: true
isLoading: false
为什么我的“isLoading”直到异步之后才为真?有没有办法确定? 我尝试将 setIsLoading(true) 向下移动到 onClick 按钮 - 我尝试使用 .then() 而不是 await 等。 - 但是 isLoading 仅在异步函数之后设置为 true。
编辑:示例 - https://codesandbox.io/s/suspicious-cartwright-0y5jk
答案 0 :(得分:1)
仅仅因为您声明了一个函数 async
并不意味着它实际上是一个异步函数,它只是允许您在内使用 await
关键字 em> 函数并隐式返回一个承诺。
在您的示例代码和框的情况下,runValidation
被声明为 async
但运行完全同步代码。
const runValidation = async () => {
let result = 0;
console.log("Running Validation");
for (let i = 1; i <= 500000; i++) {
if (i > 200000) {
result = i;
break;
}
}
return result;
};
如果您实际上执行一些异步操作,那么您会注意到控制台日志是相同的。
示例:
const runValidation = async () => {
console.log("Running Validation");
const result = await new Promise((resolve) => {
setTimeout(() => {
let result = 0;
for (let i = 1; i <= 500000; i++) {
if (i > 200000) {
result = i;
break;
}
}
resolve(result);
}, 3000);
});
return result;
};
<块引用>
Running Validation // logged immediately in callback
isLoading true // logged in useEffect next render cycle
isLoading false // logged in useEffect ~3 seconds later
const handleClick = async () => {
setIsLoading(true);
await runValidation();
setIsLoading(false);
};
在这里,您已将状态更新入队,然后立即调用 runValidation
,这将控制台日志 "Running Validation"
然后 "isLoading true"
来自 useEffect
,等待隐式 Promise (时间不长),然后另一个状态更新进入队列,"isLoading false"
从 useEffect
控制台记录。
您的代码似乎完全符合我的预期。
如果您将验证日志移入异步逻辑,那么控制台日志输出可能更像您期望的,因为您现在给 React 状态一个机会在“异步”代码完成“触发”之前更新和重新渲染。
const runValidation = async () => {
const result = await new Promise((resolve) => {
setTimeout(() => {
console.log("Running Validation");
let result = 0;
for (let i = 1; i <= 500000; i++) {
if (i > 200000) {
result = i;
break;
}
}
resolve(result);
}, 3000);
});
return result;
};
输出
<块引用>isLoading true
Running Validation
isLoading false