I'm trying to build a loading component so that my app doesn't try and display my API data before it has loaded, causing a fatal error. Read a lot about componentWillMount function but this seems to have been deprecated. Trying to use setState to no avail.
import { useEffect, useState } from "react";
import Marquee from "react-fast-marquee";
const News = () => {
const [data, setData] = useState({});
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
const getNewsFromApi = async () => {
const response = await fetch(
"API_KEY_HERE"
);
const responseJson = await response.json();
console.log("json", responseJson);
setData(responseJson);
};
setLoading(false);
setInterval(getNewsFromApi, 1000)
}, []);
if (loading) {
return <h1> Data is loading...</h1>
}
return (
<div >
<Marquee gradientColor="" speed="120">
<h1>{data?.articles[0].title} - </h1>
<h1>{data?.articles[1].title} - </h1>
<h1>{data?.articles[2].title} - </h1>
<h1>{data?.articles[3].title} - </h1>
<h1>{data?.articles[4].title} - </h1>
<h1>{data?.articles[5].title} - </h1>
<h1>{data?.articles[6].title} - </h1>
<h1>{data?.articles[7].title} - </h1>
<h1>{data?.articles[8].title} - </h1>
</Marquee>
</div>
)
}
export default News
useEffect hook runs after the render (see docs). So what's going to happen:
loading as false (by calling useState(false)).loading=false so it skips loading placeholder and tries to immediately render articles list which is {}. It means data?.articles is undefined.I would do the following changes:
const [loading, setLoading] = useState(true);
This will make component to render loading placeholder first time. 2. Using state as an array of articles instead of object that is returned from your API also makes sense (as @Bru No suggested). But you'll need to make changes in your effect - something like:
setData(responseJson.articles);
you start read infos from state before the api response i suggest to use this solution
import { useEffect, useState } from "react";
import Marquee from "react-fast-marquee";
const News = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
(async function getNewsFromApi(){
const response = await fetch(
"API_KEY_HERE"
);
const responseJson = await response.json();
console.log("json", responseJson);
setData(responseJson);
})();
setLoading(false);
}, []);
if (loading) {
return <h1> Data is loading...</h1>
}
return (
<div >
<Marquee gradientColor="" speed="120">
{data.length > 0 && data.articles.map((item)=> <h1>{item.title} </h1>)}
</Marquee>
</div>
)
}
export default News