In my React application, I am calling an async function that renders a JSX from inside array.map(), but nothing is being rendered. I confirmed that the function is being called properly.
I suspect that there is something related to the rendering being executed before the async function returns its result, but I do not understand why this would happen if the async function is using await in its internal calls
<div>
{
gallery.map((image) =>
{renderImage(image, 'vegan-mundi-gallery')}
)}
</div>
I tried wrapping the function that generates the JSX inside a React Fragment (<></>) as in the snippet below, but then I get the error "Objects are not valid as a React child (found: [object Promise])".
{
gallery.map((image) => (
// The react fragment below is generating the error Objects are not valid as a React child (found: [object Promise]) - which reinforced the idea that the async function haven’t returned its result by the time of the rendering
<>
{renderImage(image, 'vegan-mundi-gallery')}
</>
)
)}
Does anyone can help with this?
This is my complete code:
import { useEffect, useState } from "react";
export default function Gallery (){
const [isLoading, setIsLoading] = useState(true);
const [gallery, setGallery] = useState([]);
useEffect( ()=> {
// some code that gets the gallery array from an API call and handles the isLoading state
} , []);
const renderImage = async(item, bucket) => {
const photo = item.PHOTO;
const data = await fetch(`http://1.1.1.1:4000/s3/${bucket}/${photo}`);
const preSignedUrl = await data.json();
console.log(preSignedUrl) // I can see the preSignedUrl in the console, so the async call worked!
return (
<figure>
<div>
<img key={photo}
src={`${preSignedUrl}`}
/>
</div>
<figcaption>{item.LABEL}</figcaption>
</figure>
)
}
if (isLoading){
return(<p>loading...</p>);
}
else {
return (
<div>
{
gallery.map((image) =>
{renderImage(image, 'vegan-mundi-gallery')}
)}
</div>
)
}
}
I checked ChatGPT, and it suggested exactly what I have done with the <></>.
Better use useEffects to handle this situation.
const [gallery, setGallery] = useState([]);
useEffect(() => {
// Simulate API call to get gallery array
const fetchGallery = async () => {
const galleryData = [
{ PHOTO: 'photo1.jpg', LABEL: 'Label 1' },
{ PHOTO: 'photo2.jpg', LABEL: 'Label 2' },
];
setGallery(galleryData);
};
fetchGallery();
}, []);
for fetching images
const [images, setImages] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchImages = async () => {
const fetchedImages = await Promise.all(
gallery.map(async (item) => {
const photo = item.PHOTO;
const response = await fetch(`http://1.1.1.1:4000/s3/bucketname/${photo}`);
const preSignedUrl = await response.json();
return { ...item, url: preSignedUrl };
})
);
setImages(fetchedImages);
setIsLoading(false);
};
if (gallery.length > 0) {
fetchImages();
}
}, [gallery]);
if (isLoading) {
return (<p>loading...</p>);
} else {
return (
<div>
{images.map((image) => (
<figure key={image.PHOTO}>
<div>
<img src={image.url} alt={image.LABEL} />
</div>
<figcaption>{image.LABEL}</figcaption>
</figure>
))}
</div>
);
}