#Why do I need the cleanup function?

24 messages · Page 1 of 1 (latest)

clear kestrel
#

Okay, I have something here I don't quite understand, so I'll be thankful if someone can explain. I have this useEffect hook which calls two async functions that retrieve data from an API. You can see the difference between the two is that setQuestions() is not in a cleanup function on the second screenshot. Now, the code works as I expect when setQuestions() is in the cleanup function and I'm not sure why. I figured i'm creating some side effect that's causing rerenders, which then causes the hook to run multiple times and break the code. So can someone explain why does it need to be inside the cleanup function and what exactly is happening when it isn't?

wild trout
#

Are you SURE it works as expected when the setQuestions() call is IN the cleanup function? It really shouldn't... I'd be interested to see your entire code here.

It shouldn't work at all (basically) since the questions would only be fetched at unmount (since there's an empty dependency array) making me wonder just what's happening with the App component...

#

And if you're wondering why your "not in a cleanup function" variant doesn't work it's because your getData() call is async so the setQuestions() on line 18 is going to set the questions to a promise reference instead of your question data.

It should be:

useEffect(() => {
  const getData = async () => {
    const sessionToken = await getToken();
    const data = await getQuestions(sessionToken);
    localStorage.setItem('token', sessionToken);
    setQuestions(data)
    // WHOA nelly!  You've not set questions so you're
    // effectively resetting questions to the current
    // state of questions which is an empty array...
    //return questions; 
  };
  getData();
}
clear kestrel
clear kestrel
wild trout
clear kestrel
wild trout
#

You're calling it only as part of the cleanup code... See my previous post about where this should be.

clear kestrel
#

Yes, I saw that. Inside the cleanup function it actually works. If I put it out as you've shown outside the cleanup function, the hook triggers multiple times.

wild trout
#

Not really... the effect only gets triggered on mount so should only happen once. If you mean the component itself gets re-rendered then yes... Did you try my code?

clear kestrel
#

yes, it rerenders and the API returns with 429 too many requests, like in my example without the cleanup function

wild trout
#

Something's not adding up here... do you have a link to a Scrim or a GitHub repo with your code so I can debug it?

clear kestrel
#

sure, I'll put it on github and send a link

wild trout
#

👍

clear kestrel
wild trout
#

Ok, I'll take a look!

#

Ok, the 429 is NOT 429 requests - it's an error code because opentdb has a rate limit...

#

I'm sending you a PR with the working code (I've added a simple dump of the questions so you can see them)... standby

#

Ok, PR created with working useEffect

#

fwiw here's a screen shot with the dump of REAL questions:

#

If opentdb is rate limited to 1 request every 5 seconds... 429 is the error code that comes back here:

clear kestrel
#

Thank you, I think I get it now but also useEffect triggers twice. Isn't it supposed to trigger only once? What's the deal here?

wild trout
#

That's because of <StrictMode> in your main.jsx...