I'm using this API http://www.omdbapi.com/ which only returns 10 search results at a time but gives you the total amount of objects available. It is possible to add the "page" parameter to an API call.
An API call searching for "star" would look like this (the link won't work it's not a valid API key):
http://www.omdbapi.com/?apikey=keykey&s=star
And with a specific page in mind:
"http://www.omdbapi.com/?apikey=keykey&s=star&page=7"
So after a fetch with no page parameter specified I will receive the data in this format:
{
Search: [...], // An array of the first 10 search result
totalResults: "n" // The total number of result
Response: "True" // The status of the response
}
How can I loop over all of the pages and fetch all of the Search arrays in order? At the moment I have this:
const [loading, setLoading] = useState(true);
const [data, setData] = useState();
const fetchMovies = async () => {
setLoading(true);
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${searchResult}`;
try {
const response = await fetch(url);
const data = await response.json();
let movies;
const rounding = Math.ceil(data.totalResults / 10);
if (rounding > 1) {
for (let index = 1; index <= rounding; index ) {
const response = await fetch(`${url}&page=${index}`);
const data = await response.json();
const movies = [...movies, ...data.Search];
}
}
setData(movies);
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
};
useEffect(() => {
fetchMovies();
}, []);
At the moment the loop "works" in a way, the data.Search array gets added to "movies" for each pages, but while that happens the execution of the code continues, setData() gets set to nothing, setLoading() to false, and fetchMovies() returns.
I know this because if you log movies inside the loop you can see the data getting added.
How can I wait for all API calls to resolve before resuming execution, and is it possible to do it inside the first fetch? Or do I first need to get the number of pages and then queue up my API calls?
CodePudding user response:
You are declaring movies inside the for
loop again but in setData(movies)
setting the movies which is declared above as let movies;
const [loading, setLoading] = useState(true);
const [data, setData] = useState();
const fetchMovies = async () => {
setLoading(true);
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${searchResult}`;
try {
const response = await fetch(url);
const data = await response.json();
let movies = []; // Set empty array here
const rounding = Math.ceil(data.totalResults / 10);
if (rounding > 1) {
for (let index = 1; index <= rounding; index ) {
const response = await fetch(`${url}&page=${index}`);
const data = await response.json();
// You would want to push movies inside the movies array
movies.push(...data.Search);
}
}
setData(movies);
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
};
useEffect(() => {
fetchMovies();
}, []);