В моем приложении React я вызываю асинхронную функцию, которая отображает JSX изнутри array.map(), но ничего не отображается. Я подтвердил, что функция вызывается правильно.
Я подозреваю, что что-то связано с выполнением рендеринга до того, как асинхронная функция вернет свой результат, но я не понимаю, почему это произойдет, если асинхронная функция использует ожидание в своих внутренних вызовах.
<div>
{
gallery.map((image) =>
{renderImage(image, 'vegan-mundi-gallery')}
)}
</div>
Я попытался обернуть функцию, которая генерирует JSX, внутри фрагмента React (<></>), как показано в приведенном ниже фрагменте, но затем я получаю сообщение об ошибке «Объекты недействительны в качестве дочернего элемента React (найдено: [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')}
</>
)
)}
Кто-нибудь может помочь с этим?
Это мой полный код:
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.info(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>
)
}
}
Я проверил
Спасибо, что указал мне правильное направление, JW. Я изо всех сил пытался понять, как это реализовать, а затем @Dileepa Mabulage предоставил решение!
Лучше используйте useEffects, чтобы справиться с этой ситуацией.
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();
}, []);
для получения изображений
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>
);
}
Огромное спасибо, @Dileepa Mabulage! Я реализовал это так же, как в вашем примере, и он работает так, как я хотел. Загвоздка, которую я не смог выяснить самостоятельно, заключалась в переменной состояния галереи, вызывающей вызов асинхронной функции для генерации заранее подписанного URL-адреса. Молодец, сэр!
Рад, что здесь это
Я бы рекомендовал выполнять все асинхронные вызовы внутри useEffect и сохранять результаты в состоянии, чтобы избежать асинхронных вызовов при рендеринге.