等待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);
// ...
由于某种原因,我的逻辑在这里失败了;无论此时loading
是否从true
更改为false
,睡眠消息都会在1.5秒后呈现。为什么是这样?即使要在计时器到期后执行该功能,它在setTimeout
中的值是否也会立即评估?还是我在这里想念其他东西?
答案 0 :(得分:1)
您没有清除上一个超时。
useEffect(() => {
const timeoutId = setTimeout(() => {
if (loading) setSleepMessage("The server seems to be sleeping. Waking it up, wait a second...");
}, 1500);
return () => clearTimeout(timeoutId);
}, [loading]);
答案 1 :(得分:1)
首先,查询正在加载,因此loading
的值为true,将setTimeout放入JS调用堆栈,并保持loading
的值为true,在放置1.5s后进入任务队列。经过几次滴答之后,调用堆栈为空,它将把setTimeout内的回调函数放回调用堆栈,并执行setSleepMessage
。因此,无论加载是true还是false,为什么在1.5秒后呈现睡眠消息。您应该在clearTimeout
中使用useEffect
来防止这种情况发生。
您可以在JS中阅读有关event loop
的更多信息,以进行更深入的研究。
答案 2 :(得分:1)
您需要通过返回清除超时的函数来清理效果。我建议也仅在loading
为true时才启动超时。
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]);