Image of the unwanted behaviourI'm using DaisyUi / Tailwindcss to render a Carousel and it's child item. The item are images that are fetched from a firebase storage.
The issue is when I try to map the image urls, which is a state of an array of strings, I only get 1 image instead of all the items.
There's 2 items in my storage and it's complete when I log it's content / arrays' length but the state(imageUrls) is not filled and it only shows 1 item.
Ask for any clarification. Here is my code for my carousel component.
const MyCarousel = () => {
const [imageUrls, setImageUrls] = useState<string[]>([]);
const storage = useStorage();
const getImages = async () => {
const storageRef = ref(storage, 'Tech/');
const files = await listAll(storageRef);
const imageAppender: string[] = Array(files.items.length);
console.log('img', imageAppender.length);
files.items.forEach(async (item, key) => {
const imageRef = ref(storage, item.fullPath);
getDownloadURL(imageRef).then((url) => {
imageAppender[key] = url;
setImageUrls(imageAppender);
});
});
};
useEffect(() => {
getImages();
}, []);
return (
<>
<div className="carousel w-full">
{imageUrls.map((image, key) => {
return (
<div key={key} id={'item' key} className="carousel-item w-full">
<img src={image} className="w-full" />
</div>
);
})}
</div>
<div className="flex justify-center w-full py-2 gap-2">
{imageUrls.map((_, key) => {
return (
<a key={key} href={'#item' key} className="bth btn-ghost btn-circle text-center">
{key}
</a>
);
})}
</div>
</>
);
};
export default MyCarousel;
CodePudding user response:
Problem is with the way you update your imageUrls state. You always pass same imageAppender in your setImageUrls, so in that case DOM is re-rendered only after first setImageUlrs state update.
files.items.forEach(async (item, key) => {
const imageRef = ref(storage, item.fullPath);
getDownloadURL(imageRef).then((url) => {
setImageUrls(currentUlrs => {
const updatedUrls = [...currentUlrs];
updatedAppender[key] = url;
return updatedAppender;
});
});
})
Please read useState functional updates - to get latest state on update. So basically you need to pass new reference to new array (create updatedAppender) to trigger re-render.
In addition It is better to not use forEach with async tasks. Please read this thread for alternatives What is the difference between async/await forEach and Promise.all map