I'm new to React and I'm trying to create a component that displays a list of "listings" which contain the ids of books from the Google books api. Each listing will ideally display information about the book and the user that posted the listing. Right now, I have a FeedList component and a FeedElement component -- FeedList fetches listings from our database and then uses a map function to return FeedElement components for each listing. Each listing has a book_id and a user_id field. In FeedElement, I fetch book data from the Google books api and user data from our database. The response from Google books is a json, where you can access information in the book through the volumeInfo field (eg. book.volumeInfo.title).
FeedList.js
export default function FeedElements () {
const [listings, setListings] = useState([]);
useEffect(() => {
async function getListings() {
const response = await fetch(`...`);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
window.alert(message);
return;
}
const listings = await response.json();
setListings(listings);
}
getListings();
return;
}, [listings.length]);
function getListingInfo() {
return listings.map((listing) => {
return (
<FeedElement listing={listing} key={listing._id}/>
)
});
}
return (
...
{getListingInfo()}
);
}
FeedElement.js
export default function FeedElement(props) {
const listing = props.listing;
const [book, setBook] = useState([]);
const [bookInfo, setBookInfo] = useState([]);
const [user, setUser] = useState([]);
useEffect(() => {
async function getBook(id) {
const response = await fetch(`...`);
if (!response.ok) {
const message = `An error occurred, Book: ${response.statusText}`;
window.alert(message);
return;
}
const book = await response.json();
if (!book) {
window.alert(`Book with id ${id} not found`);
return;
}
return book;
}
async function getUser(id) {
const response = await fetch(`...`);
if (!response.ok) {
const message = `An error occurred, User: ${response.statusText}`;
window.alert(message);
return;
}
const user = await response.json();
if (!user) {
window.alert(`User with id ${id} not found`);
return;
}
return user;
}
async function getAll() {
const tempLoadedBook = await getBook(listing.book_id);
const tempLoadedUser = await getUser(listing.user_id);
setBook(tempLoadedBook);
setUser(tempLoadedUser);
setBookInfo(tempLoadedBook.volumeInfo); // <--- Here
}
getAll();
return;
}, [listing.book_id, listing.user_id]);
if (typeof(bookInfo) === "undefined" || bookInfo.length === 0) {
return <div>Loading...</div>;
}
return (
<div className="feed-single">
<h2 className="book-info-title">{bookInfo.title}</h2>
<h3>{bookInfo.authors[0]}</h3>
</div>
);
}
The issue I'm having is that after the book is fetched from Google books, some data (title, authors) hasn't loaded within the response when the component renders, so when I call bookInfo or book.volumeInfo it comes back as undefined. I added an if statement before the return to catch when bookInfo hasn't loaded yet, however, the component only renders with the text 'Loading...' and never fills in with the correct info. I've also tried using {bookInfo && bookInfo.title} in the html, but it just causes the book info to never load.
Any help or ideas would be appreciated! Again, I'm very new at this and not sure what to do from here.