Получение и отображение изображений из firebase в приложении React. js - PullRequest
0 голосов
/ 25 мая 2020

, поэтому я пытаюсь получить изображения из хранилища Firebase, а затем отобразить их в компоненте React. Честно говоря, я новичок в React / Javascript, и мне трудно понять асинхронный характер React / JS, и я столкнулся с проблемой, когда мои изображения загружаются, но компонент не повторно отображается после завершения выборки ...

Это код на моей главной странице, в функции useEffect я пытаюсь получить изображения, а затем сохранить их URL-адреса загрузки в массиве, а затем установить этот массив в состоянии (при загрузке страницы, т.е. только один раз). Поскольку это обещания, это не происходит синхронно, и когда я впервые загружаю страницу, на ней не отображаются изображения. Однако если я щелкну другой компонент на странице, он повторно отобразит мой компонент «Изображения», и изображения появятся (??), поэтому я знаю, что выборка сработала.

    let storageRef = firebase.storage().ref()
    let calendarRef = React.createRef()

    const position = props.location.state.name.indexOf("@")
    const username = props.location.state.name.substring(0, position);

    const [simpleDate, setSimpleDate] = useState(null)
    const [selectedDate, setSelectedDate] = useState('')
    const [showModal, setShowModal] = useState(false)
    const [showCancelModal, setShowCancelModal] = useState(false)
    const [expectedPeople, setExpectedPeople] = useState(null)
    const [events, setEvents] = useState([])
    const [helpModal, showHelpModal] = useState(false)

    const [pictureURLs, setPictureURLs] = useState([])


    useEffect(() => {

        //load pictures
        const fetchImages = async () => {
            let urls = []
            storageRef.child('cabinPictures').listAll().then((result) => {
                result.items.forEach((imageRef) => {
                    imageRef.getDownloadURL().then(url => {
                        urls.push(url)
                    })
                })
            })
            return urls;
        }

        fetchImages().then(urls => {
            setPictureURLs(urls);
            console.log("inside .then() " + pictureURLs)
        })


        //fetch reservations
        firebase
            .firestore()
            .collection('reservations')
            .onSnapshot(serverUpdate => {
                const reservations = serverUpdate.docs.map(_doc => {
                    const data = _doc.data();
                    data['id'] = _doc.id;
                    return data;
                });

                let fetchedEvents = reservations.map(reservation => {
                        let date = reservation.reservationDate.toDate()
                        const month = ("0" + (date.getUTCMonth() + 1))
                        let dateString = date.getUTCFullYear() + "-" + ("0" + (date.getUTCMonth()+1)).slice(-2) + "-" + ("0" + date.getUTCDate()).slice(-2)
                        return {title: reservation.username + " - " + reservation.numPeople + " total", date: dateString, id: reservation.id, totalPeople: reservation.numPeople, month: month}
                    })
                console.log(fetchedEvents)
                setEvents(fetchedEvents)
            });
    }, [])    

Мои изображения компонент на главной странице, где запускается useEffect (см. выше). Я передаю URL-адреса из состояния в качестве опоры:

<div className="pictures-div-container">
      <Pictures pictureURLs={pictureURLs}>

      </Pictures>
 </div>

Код для моего компонента Picture:

import React, { useState, useEffect } from 'react'
import styles from "./styles.css"

const firebase = require('firebase');


const Pictures = (props) => {

    const [uploadImage, setUploadImage] = useState(null)
    const [progressValue, setProgressValue] = useState(0)

    let storageRef = firebase.storage().ref()
    let { pictureURLs } = props


    const handleUpload = () => {
        setProgressValue(0)

        const uploadTask = storageRef.child(`cabinPictures/${uploadImage.name}`).put(uploadImage)
        uploadTask.on('state_changed', 
        (snapshot) => {
            //progress function
            const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes ) * 100)
            setProgressValue(progress)
        }, 
        (error) => {
            //error function
            console.log(error)
        },
        () => {
            //complete function
            storageRef.child('cabinPictures').child(uploadImage.name).getDownloadURL().then(url => {
                console.log(url)
            } )
        });
    }

    const handleFileSelect = (e) => {
        if (e.target.files[0]) {
            setUploadImage(e.target.files[0])
        }
    }

    return (
        <div className="pictures-container">
            <h2>Upload a Picture!</h2>
            <button className="upload-button" onClick={() => handleUpload()}>Upload</button>
            <input type="file" onChange={(e) => handleFileSelect(e)}></input>
            <progress value={progressValue} max="100"></progress>
            <div className="pictures"> 
                {
                    pictureURLs.map((url, index) => {
                        return <img className="picture" key={index} src={url}></img>

                    })
                }
            </div>
        </div>
    )
}

export default Pictures

Итак, может ли кто-нибудь помочь мне понять, почему компонент изображений не повторно- рендеринг автоматически, когда состояние установлено после получения URL-адресов изображений из firebase? Я думал, что при изменении опоры в компоненте, весь компонент перерисовывается? 1014 *

        //fetch and load pictures
        const fetchImages = async () => {

            let result = await storageRef.child('cabinPictures').listAll();
            let urlPromises = result.items.map(imageRef => imageRef.getDownloadURL())

            return Promise.all(urlPromises)
        }

        const loadImages = async () => {
            const urls = await fetchImages()
            setPictureURLs(urls)
        }

        loadImages()

1 Ответ

0 голосов
/ 25 мая 2020

Вы должны позволить всем вложенным обещаниям разрешиться, прежде чем вы return urls

Я не очень хорошо разбираюсь в API Firebase, поэтому не уверен, что result.items является фактическим массивом или объектом, который имеет foreach метод. Следующее должно работать, если это js массив

Попробуйте что-то вроде:

//load pictures
const fetchImages = async() => {

  let result = await storageRef.child('cabinPictures').listAll();
  /// map() array of the imageRef.getDownloadURL() promises 
  let urlPromises = result.items.map(imageRef => imageRef.getDownloadURL());

  // return all resolved promises
  return Promise.all(urlPromises);
}

const urls = await fetchImages()
setPictureURLs(urls);
console.log("inside .then() ", urls) 
...