2 years ago
#19761
Dashiell Rose Bark-Huss
React not rendering element if async call for data takes too long
I'm grabbing user data from an API. The API call takes a while. But even when the frontend gets the response, React never finishes rendering the component.
I can replicate this behavior with setTimeout
.
A small timeout like 7ms
will work, but if I use a larger timeout like 700ms
<h1>Text rendered!</h1>
doesn't display.
useEffect(() => {
setTimeout(() => setUsers({ data: ["user1", "user2", "user3"] }), 700);
}, []);
In the debugger I can see that the flow seems to be working
- The frontend receives the response, and calls
setUser
. - This triggers the second
useEffect
callback which updatesusers
. - This re-renders the component, and
users && users.updated
is true, but then<h1>Text rendered!</h1>
doesn't render for some reason.
Oddly though, on codesandbox, I get completely different behavior: <h1>Text rendered!</h1>
never renders, even if I use a small timeout like 1ms, or even if I just use setUsers
with no setTimeout
. And on my local environment, sometimes 700ms
does work if I step through it in the debugger slowly but I can't always replicate this.
What's going on? How can I get {users && users.updated && <h1>Text rendered!</h1>}
to render properly on longer asynchronous calls?
Full code:
import React, { useEffect, useState } from "react";
export default function App() {
const [users, setUsers] = useState(null);
// 1. Get Data from API
useEffect(() => {
//----replicating asyncronous API call----
//"Text rendered!" doesn't render if the timeout is large (700ms)
//but does render if timeout is small (2ms)
//(On codesandbox "Text rendered!" never renders, even if you don't use a timeout just use setUsers)
setTimeout(() => setUsers({ data: ["user1", "user2", "user3"] }), 2);
}, []);
// 2. Once Data is Receive from API, Transform It
useEffect(() => {
if (users) {
const usersCopy = users;
usersCopy.updated = true;
setUsers(usersCopy);
}
}, [users]);
// 3. After the Data is Transformed, Render "Text Rendered!"
return (
<>
Render text below:
{users && users.updated && <h1>Text rendered!</h1>}
</>
);
}
javascript
reactjs
asynchronous
codesandbox
0 Answers
Your Answer