Reputation: 457
I'm trying to render a loading message after 1.5 seconds of waiting, if the thing is still loading:
useEffect(() => {
setTimeout(() => {
if (loading) setSleepMessage("The server seems to be sleeping. Waking it up, wait a second...");
}, 1500);
}, [loading]);
The variable loading
is a boolean in state returned by an Apollo hook, and setSleepMessage
is hooked to state too:
import { useQuery } from "@apollo/client";
import React, { useState, useEffect } from "react";
// ...
const [ sleepMessage, setSleepMessage ] = useState<string>();
const { data , loading } = useQuery(SOME_QUERY);
// ...
For some reason my logic fails here; the sleep message is rendered after 1.5 seconds no matter whether loading
has changed from true
to false
at that point. Why is this? Is its value in setTimeout
evaluated right away even though the function is to be executed after the timer expires? Or am I missing something else here?
Upvotes: 2
Views: 5077
Reputation: 202836
You need to clean up your effects by returning a function to clear the timeout. I suggest also only initiating the timeout if loading
is 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]);
Upvotes: 1
Reputation: 1872
Firstly, the query is loading so the value of loading
is true, the setTimeout will be put into JS call stack and keep the value of loading
is true, after 1,5s it is put into task queue. After some ticks, the call stack is empty, it will put the callback function inside setTimeout back to callstack and setSleepMessage
is executed. So that why the sleep message is rendered after 1.5 seconds no matter whether loading is true or false. You should clearTimeout
in useEffect
to prevent this happens.
You can read more about event loop
in JS to dive deeper.
Upvotes: 1
Reputation: 494
You didn't clear the previous timeout.
useEffect(() => {
const timeoutId = setTimeout(() => {
if (loading) setSleepMessage("The server seems to be sleeping. Waking it up, wait a second...");
}, 1500);
return () => clearTimeout(timeoutId);
}, [loading]);
Upvotes: 2