# #javascript #reactjs #firebase #google-cloud-firestore
Вопрос:
Кажется, что массив «изображения» сначала пуст, а элементы добавляются позже, когда данные извлекаются из firestore, но состояние реакции не обновляется, поэтому изображение не отображается, хотя я использовал ожидание везде, где это возможно.
useEffect(() =gt; { 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(); }, []);
отображение изображений:
const handleGetImages = (images) =gt; { console.log("images", images); // image is first empty and then populated after the html has been rendered return images.map((imageData) =gt; { return ( lt;Grid.Column key={imageData.url}gt; lt;span class="image left"gt; lt;img src={imageData.url} style={styles.image} alt="" /gt; lt;/spangt; lt;/Grid.Columngt; ); }); };
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) =gt; { 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; }
Есть какой-нибудь способ это исправить? Спасибо!
Ответ №1:
Ваш код близок. Array.prototype.forEach
однако это синхронно. Я подозреваю, что ваша downloadAllImages
функция не ждет завершения обратных вызовов цикла и возвращает images
массив, который еще не заполнен.
Переработайте логику, чтобы создать массив обещаний (функции async
обратного вызова) и дождаться Promise.all
их, тогда у вас будет заполненный массив изображений для возврата.
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) =gt; { 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); }
Комментарии:
1. Большое вам спасибо! Я потратил на это так много времени, ха-ха, это сработало идеально! Только одно, там написано, что querySnapshot.map-это не функция, думаю, она должна
querySnapshot.docs.map(...)
быть.2. @guckmalmensch Спасибо, обновил свой ответ, чтобы отразить это.