如何在 React 中延迟后有条件地改变 useEffect 中的状态?
2020-08-13
4816
如果内容仍在加载,我尝试在等待 1.5 秒后呈现加载消息:
useEffect(() => {
setTimeout(() => {
if (loading) setSleepMessage("The server seems to be sleeping. Waking it up, wait a second...");
}, 1500);
}, [loading]);
变量
loading
是 Apollo 钩子返回的状态中的布尔值,并且
setSleepMessage
也挂钩到状态:
import { useQuery } from "@apollo/client";
import React, { useState, useEffect } from "react";
// ...
const [ sleepMessage, setSleepMessage ] = useState<string>();
const { data , loading } = useQuery(SOME_QUERY);
// ...
由于某种原因,我的逻辑在这里失败了;睡眠消息会在 1.5 秒后呈现,无论此时
loading
是否已从
true
更改为
false
。这是为什么?即使该函数要在计时器到期后执行,也会立即评估其在
setTimeout
中的值吗?还是我在这里遗漏了其他东西?
3个回答
您需要通过返回一个函数来清除超时,从而清理效果。我建议仅在
loading
为真时才启动超时。
useEffect(() => {
let timerId;
if (loading) {
timerId = setTimeout(() => {
setSleepMessage(
"The server seems to be sleeping. Waking it up, wait a second..."
);
}, 1500);
}
return () => clearTimeout(timerId);
}, [loading]);
Drew Reese
2020-08-13
您没有清除之前的超时。
useEffect(() => {
const timeoutId = setTimeout(() => {
if (loading) setSleepMessage("The server seems to be sleeping. Waking it up, wait a second...");
}, 1500);
return () => clearTimeout(timeoutId);
}, [loading]);
Danilo Gacevic
2020-08-13
首先,查询正在加载,因此
loading
的值为 true,setTimeout 将被放入 JS 调用堆栈并保持
loading
的值为 true,1.5 秒后将其放入任务队列。经过几个 ticks 后,调用堆栈为空,它会将 setTimeout 中的回调函数放回调用堆栈并执行
setSleepMessage
。因此,无论加载是 true 还是 false,睡眠消息都会在 1.5 秒后呈现。您应该在
useEffect
中使用
clearTimeout
来防止这种情况发生。
您可以阅读有关 JS 中的
事件循环
的更多信息以深入了解。
Michael
2020-08-13