J'essaie de ne pas écrire tout mon code dans le même fichier et d'extraire les fonctions couramment utilisées comme le téléchargement d'une image depuis Firebase pour séparer les fonctions / fichiers.

J'ai deux fonctions dans React nommées

  1. OfferCard (rend une carte basée sur des accessoires)
  2. getImage (récupère l'URL de téléchargement d'une image à partir de Firebase Storage, pour fournir une image au composant OfferCard).

J'essaie de récupérer un fichier image de getImage et d'afficher cette image dans la propriété d'image <CardMedia /> renvoyée par le composant fonctionnel OfferCard.

Le problème auquel je suis confronté est que getImage ne récupère pas les données et ne les renvoie pas à temps pour le setOfferImage. Cela signifie que la variable d'état offerImage reste null ou undefined.

Dans la console, je peux voir que la console getImage enregistre la valeur APRÈS la console OfferCard enregistre la valeur /.

Je pense que c'est un problème avec le code asynchrone et les promesses, mais je ne sais pas trop comment résoudre celui-ci.

OfferCard.js:

import getImage from '../utils/helperFunctions/getImage';

export default function OfferCard(props) {
    const classes = useStyles();
    const [offerImage, setOfferImage] = React.useState(null)

    useEffect(() => {
        if (props.image) {
            initFirebase();
            setOfferImage(getImage(props.image));
            console.log(offerImage)
        }
    }, [])

    return (

        <Link href={`/offers/${props.id}`}>
            <Card className={classes.card} >
                {offerImage ? 
                    <CardMedia
                    image={offerImage}
                /> : <CircularProgress/>
                }
           </Card>
        </Link>
    )
}

getImage:

export default function getImage(path) {
    let storage = firebase.storage();
    let pathReference = storage.ref(`${path}.png`);

    pathReference.getDownloadURL()
        .then((url) => {
            console.log("returning", url);
            return (url);
        })
        .catch((error) => {
            // Handle any errors
            console.log("Could not get image: ", error);
        });
}

0
Jarrod Watts 31 août 2020 à 12:01

2 réponses

Meilleure réponse

Le problème est que votre fonction getImage est en fait une fonction vide, car elle atteindra la fin du code sans trouver de retour, car le return(url) est exécuté sur un second moment. La solution est de rendre cette fonction asynchrone, en retournant une promesse:

export default async function getImage(path) {
  let storage = firebase.storage();
  let pathReference = storage.ref(`${path}.png`);

  return new Promise((resolve, reject) => {
    pathReference.getDownloadURL()
      .then((url) => {
        console.log("returning", url);
        resolve(url);
      })
      .catch((error) => {
        // Handle any errors
        reject(error)
        console.log("Could not get image: ", error);
      });
  })
}

Pour que vous puissiez ensuite l'attendre dans votre useEffect. Sachez que vous ne pouvez pas réellement attendre à l'intérieur d'un useEffect (en savoir plus), donc votre OfferCard.js deviendra

useEffect(() => {
  const getImageAsync = async () => {
    const url = await getImage(props.image)
    if (url)
      setOfferImage(url)
    else {
      // handle error
    }
  }

  if (props.image) {
    initFirebase();
    getImageAsync();
  }
}, [])
1
Nicola Elia 31 août 2020 à 11:59
useEffect(() => {
  const fetchImg = async () => {
    const res = await getImage(props.image)
    setOfferImage(res);
    // `setOfferImage` is async 
    // `console.log(offerImage)` there will be console previous value of `offerImage`
  }
  if (props.image) {
    initFirebase();
    fetchImg()
  }
}, [props.image])
1
Liu Lei 31 août 2020 à 09:09