It seems "images" array is first empty and the elements are added later when data is fetched from firestore - but the React state won't update, so no image is displayed, although I used await everywhere possible.
useEffect(() => {
async function getAllImages() {
const images = await imageStorage.downloadAllImages(true);
// images is first empty and then populated after the html has been rendered
setImages(images);
}
getAllImages();
}, []);
display images:
const handleGetImages = (images) => {
console.log("images", images); // image is first empty and then populated after the html has been rendered
return images.map((imageData) => {
return (
<Grid.Column key={imageData.url}>
<span class="image left">
<img src={imageData.url} style={styles.image} alt="" />
</span>
</Grid.Column>
);
});
};
imageStorage.js
export async function downloadAllImages(thumbnail) {
const imageRef = collection(db, "images");
console.log("hi");
var images = [];
const q = query(imageRef, orderBy("date", "desc"), limit(10));
const querySnapshot = await getDocs(q);
querySnapshot.forEach(async (doc) => {
var imagePath = doc.data().ref; // image/task/...
if (thumbnail) imagePath = imagePath.replace("images", "thumbnails");
// GET metadata of the image
const imageRef = ref(storage, imagePath);
// GET [imagePrefix] URL
const url = await getDownloadURL(imageRef);
const fullMetadata = await getMetadata(imageRef);
images.push({
path: imagePath,
url: url,
metadata: fullMetadata.customMetadata,
});
});
return images;
}
Any way to fix this? Thanks!
CodePudding user response:
Your code is close. Array.prototype.forEach
is synchronous though. I suspect your downloadAllImages
function isn't waiting for the loop callbacks to complete and returns the images
array not populated yet.
Refactor the logic to create an array of Promises (the async
callback functions) and await Promise.all
them, then you'll have a populated array of images to return.
export async function downloadAllImages(thumbnail) {
const imageRef = collection(db, "images");
const q = query(imageRef, orderBy("date", "desc"), limit(10));
const querySnapshot = await getDocs(q);
// Map querySnapshot docs to array of async functions (Promises)
const imageRequests = querySnapshot.docs.map(async (doc) => {
const imagePath = doc.data().ref; // image/task/...
if (thumbnail) imagePath = imagePath.replace("images", "thumbnails");
// GET metadata of the image
const imageRef = ref(storage, imagePath);
// GET [imagePrefix] URL
const url = await getDownloadURL(imageRef);
const fullMetadata = await getMetadata(imageRef);
// Return image objects
return {
path: imagePath,
url: url,
metadata: fullMetadata.customMetadata,
};
});
// Return array of resolved promises (i.e. the image objects)
return Promise.all(imageRequests);
}