Reputation: 656
Currently I feel like the more I read about React, the less I understand.
I am trying to solve this simple problem: During the data-fetching for my component, show a loading spinner.
This is how I thought it would work:
use State to monitor loading
const [isLoading, setIsLoading] = useState(false);
use conditional rendering on this state
return ({isLoading && <div>I am loading</div>});
setLoading when api call is started and reset it when a reponse arrived
useEffect(() => {
const fetchData = async () => {
let result;
setIsLoading(true);
result = await api.get(URL); // this takes 2000ms!
setData(result.data);
setIsLoading(false);
};
fetchData();
},[api]);
But, as the documentation says, setState
is async and can be sent in batches. the network call takes 2 seconds, but I never see a loading animation.
So how do I do this?
Edit: This is how you can do this. My error was somewhere else - the setIsLoading(false)
was also in a different useEffect
, which had the data as dependency. I had to wrap the entire logic inside that useEffect
with if(data)
, since on the first render, my data was undefined, but this still triggered the initial useEffect
, probably like the old componentDidMount logic I guess - and the loading anim stopped way too soon.
Upvotes: 0
Views: 3612
Reputation: 13912
I think what you've got there works. I've implemented it here: codesandbox
import "./styles.css";
import React, { useState, useEffect } from "react";
export default function App() {
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
let result;
setIsLoading(true);
result = await api.get(URL); // this takes 2000ms!
//setData(result.data);
setIsLoading(false);
};
fetchData();
}, []);
return (
<div className="App">
{isLoading ? <p>currently loading</p> : null}
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const api = {
get: async function () {
await new Promise((r, e) => setTimeout(r, 2000));
}
};
Upvotes: 3