React:useState():在正在进行的获取期间获取数据不起作用
React: useState(): Fetching data during an ongoing fetch does not work
我想通过 API 获取数据来显示纽约时报畅销书列表。但是,必须从 Google 书籍 API 中获取封面链接,因为纽约时报 API 不提供它们。
因此,我想用获取的数据映射一个列表。在我从 NYT API 获取数据的同一步骤中,Google Books API 的数据也应该被获取。因此,我使用 await
关键字让代码等待第二次提取完成。
但是,不幸的是,虽然承诺已经兑现,但列表并没有更新,并且已经获取了数据。 bestsellerlist
变量是一个已兑现承诺的数组,但没有我可以访问的“真实数组”。
我想应该可以拆分提取,并用两个数组创建列表:一个包含纽约时报 API 数据,另一个包含 Google 书籍 API 数据。不过,我想知道如何修复代码,这样我就可以获取所有数据并一步创建列表。
const fetchLinkCover = async (isbn) => {
const res = await fetch(googleApi(isbn));
const json = await res.json();
return json.items[0].volumeInfo.imageLinks.smallThumbnail;
};
useEffect(() => {
fetch(nytimesApi)
.then((res) => res.json())
.then((json) => {
const fetchedBookList = json.results.books;
setBestsellerList(
fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
})
);
});
}, []);
console.log(bestsellerList);
console after executing the code
.map
对 promise 没有做任何特别的事情。如果您 return 来自 map 函数的承诺(异步函数总是 return 承诺),那么 .map
将创建一个承诺数组。它不会等待那些承诺来解决。
要等待一系列承诺,您可以使用 Promise.all
将它们组合成一个承诺。然后,您可以根据该承诺调用 .then
,或者将您的代码放入 async
函数中并 await
它。
与.then
:
fetch(nytimesApi)
.then((res) => res.json())
.then((json) => {
const fetchedBookList = json.results.books;
const promises = fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
});
return Promise.all(promises);
})
.then((books) => {
setBestsellerList(books);
});
或 async
/await
:
useEffect(() => {
const fetchBooks = async () => {
const res = await fetch(nytimesApi);
const json = await res.json();
const fetchedBookList = json.results.books;
const promises = fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
});
const books = await Promise.all(promises);
setBestsellerList(books);
};
fetchBooks();
}, []);
我想通过 API 获取数据来显示纽约时报畅销书列表。但是,必须从 Google 书籍 API 中获取封面链接,因为纽约时报 API 不提供它们。
因此,我想用获取的数据映射一个列表。在我从 NYT API 获取数据的同一步骤中,Google Books API 的数据也应该被获取。因此,我使用 await
关键字让代码等待第二次提取完成。
但是,不幸的是,虽然承诺已经兑现,但列表并没有更新,并且已经获取了数据。 bestsellerlist
变量是一个已兑现承诺的数组,但没有我可以访问的“真实数组”。
我想应该可以拆分提取,并用两个数组创建列表:一个包含纽约时报 API 数据,另一个包含 Google 书籍 API 数据。不过,我想知道如何修复代码,这样我就可以获取所有数据并一步创建列表。
const fetchLinkCover = async (isbn) => {
const res = await fetch(googleApi(isbn));
const json = await res.json();
return json.items[0].volumeInfo.imageLinks.smallThumbnail;
};
useEffect(() => {
fetch(nytimesApi)
.then((res) => res.json())
.then((json) => {
const fetchedBookList = json.results.books;
setBestsellerList(
fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
})
);
});
}, []);
console.log(bestsellerList);
console after executing the code
.map
对 promise 没有做任何特别的事情。如果您 return 来自 map 函数的承诺(异步函数总是 return 承诺),那么 .map
将创建一个承诺数组。它不会等待那些承诺来解决。
要等待一系列承诺,您可以使用 Promise.all
将它们组合成一个承诺。然后,您可以根据该承诺调用 .then
,或者将您的代码放入 async
函数中并 await
它。
与.then
:
fetch(nytimesApi)
.then((res) => res.json())
.then((json) => {
const fetchedBookList = json.results.books;
const promises = fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
});
return Promise.all(promises);
})
.then((books) => {
setBestsellerList(books);
});
或 async
/await
:
useEffect(() => {
const fetchBooks = async () => {
const res = await fetch(nytimesApi);
const json = await res.json();
const fetchedBookList = json.results.books;
const promises = fetchedBookList.map(async (item) => {
const linkCover = await fetchLinkCover(item.isbns[0].isbn13);
return {
title: item.title,
authors: item.author,
ranking: item.rank,
cover: linkCover,
};
});
const books = await Promise.all(promises);
setBestsellerList(books);
};
fetchBooks();
}, []);