Reputation: 7
I am trying to fetch data from an api and push it into an array and then map through it and render it on page but when i try to map through array i got nothing. Here is my code:
let dataUrlNoPage = `https://api.themoviedb.org/3/movie/top_rated?api_key=${process.env.REACT_APP_TMDB_KEY}&language=en-US&page=`;
let top100Array = [];
const fetchData = () => {
for (let i = 1; i <= 5; i++) {
fetch(dataUrlNoPage + i)
.then((res) => res.json())
.then((data) => {
console.log(data);
if (!data.errors) {
for (let i = 0; i < data.results.length; i++) {
top100Array.push(data.results[i]);
}
return top100Array;
} else {
setResults([]);
console.log('error');
}
});
}
};
fetchData();
console.log(top100Array);
I can see top100Array in console right here.
const listItems = top100Array.map((movie) => (
<li key={movie.id}>
<TopListCard movie={movie} />
</li>
));
return (
<div className="container">
<div className="row">
<div className="col s12 m6">
<div className="add-content">
<h1>Top 20</h1>
<ul className="results">{listItems}</ul>
{console.log(listItems)}
</div>
</div>
</div>
</div>
);
};
But i get empty page here. Thanks for the help.
Upvotes: 0
Views: 120
Reputation: 371168
Rather than mutating the top100Array
(and then returning it from the .then
for some reason), you should use state that gets set with the asynchronous results, so as to force a re-render. Use Promise.all
to wait for each fetch to finish.
const [results, setResults] = useState();
const getData = i => fetch(dataUrlNoPage + i)
.then((res) => res.json())
.then((data) => {
if (data.errors) {
console.log(data.errors);
throw new Error(data.errors);
}
return data.results;
// Retrieve results only once, on mount:
useEffect(() => {
Promise.all(
Array.from({ length: 5 }, (_, i) => getData(i + 1))
)
.then((allResults) => {
setResults(allResults.flat());
})
.catch(handleErrors);
}, []);
Then render it:
<ul className="results">{results ? listItems(results) : null}</ul>
replacing the JSON.stringify
with however you want to transform the resulting array into JSX elements. (maybe you'd want results.map(result => <span>result.title</span>)
, or something like that)
Upvotes: 3
Reputation: 21
Everything looks fine to me. You actually don't need to return top100Array
. The only thing I can think of is that you render your list before top100Array
is filled with items.
Upvotes: -1
Reputation: 1547
Not sure what is returned and the for loop is not optimal, but you might as well map directly in the jsx
<ul className='results'>
{top100Array.map((movie) => (
<li key={movie.id}>
<TopListCard movie={movie} />
</li>
))}
</ul>
Upvotes: -1