Как я могу отображать изображения в React из хранилища firebase?

# #javascript #mysql #reactjs #firebase-storage #use-effect

Вопрос:

Здесь я пытаюсь получить список продуктов из базы данных MySQL, и для каждого объекта продукта я назначаю новое свойство — ImageUrl с помощью getImages(). Когда я регистрирую список продуктов в консоли, появляется свойство ImageUrl с правильным URL-адресом. Проблема в том, что когда я пытаюсь нанести его на карту, он ничего не показывает. Почему?

 const storageRef = firebase.storage().ref("/assets")

const [productList, setProductList] = useState([])

useEffect(() => {
    Axios.get("http://localhost:3001/product/get").then((response) => {
        setProductList(response.data)
    })  
}, [])

useEffect(() => {
    getImages(productList)
}, [productList])


const getImages = (array) => {
    array.forEach((item) => {
        storageRef.child(`${item.bannerImage}`).getDownloadURL().then((url) => {
            item.imageURL = url
        })
    })
}
 

Моя функция карты:

 {productList.map((val) => {
    return (
        <div key={val.id} className="product">
            <div className="item">
                <h1>Product title: {val.title}</h1>
                <h2>Price: {val.price}</h2>
                <h2>Quantity: {val.quantity}</h2>
                <h2>IMAGE: {val.imageURL}</h2>
            </div>
        </div>
    ) 
})}
 

Ответ №1:

Проблемы:

  1. Вы не productList возвращаетесь к getImages работе. Вы просто перебираете массив.
  2. getDownloadURL это async функция, вы не должны использовать ее внутри цикла. Лучший способ сделать это-с помощью recursive функции. Но вы также можете сделать это, как показано ниже:

Решение

Ваша getImage функция

 const getImage = async (bannerImage) => {
     const url = await storageRef.child(bannerImage).getDownloadURL();
     return url;   
}
 

тогда ваша map функция

 {productList.map((val) => {
    return (
        <div key={val.id} className="product">
            <div className="item">
                <h1>Product title: {val.title}</h1>
                <h2>Price: {val.price}</h2>
                <h2>Quantity: {val.quantity}</h2>
                <h2>IMAGE: {getImage(val.bannerImage)}</h2>
            </div>
        </div>
    ) 
})}
 

Комментарии:

1. Спасибо! Но теперь он выдает ошибку: Ошибка: Объекты недопустимы в качестве дочернего элемента React (найдено: [обещание объекта]). Если вы хотели отобразить коллекцию дочерних элементов, вместо этого используйте массив. Эта ошибка указывает на setProductList() в useEffect().

2. Хорошо, не могли бы вы, пожалуйста, сказать мне, что такое val.bannerImage, выполнив console.log? Это веревочка или что-то еще!

3. Это [обещание объекта]

4. Обещание {<в ожидании>} <в ожидании> прото : Обещание [[Обещание]]: «выполнено» [[Обещание]]: «<URL к изображению>»

5. И не могли бы вы, пожалуйста, проверить url внутреннюю сетку, а также в консоли?

Ответ №2:

Я бы посоветовал вам создать еще один небольшой компонент для рендеринга изображений и обрабатывать асинхронное getDownloadURL поведение внутри этого компонента

 function ProductImage({bannerImage}) {
  const [imageUrl, setImageUrl] = useState('')
  
  useEffect(() => {
    async function getImage(bannerImage) {
      const url = await bannerImage.getDownloadURL()
      setImageUrl(url)
    }
    getImage(bannerImage)
  }, [bannerImage])

  return imageUrl ? <h2>IMAGE: {imageUrl}</h2> : '...Loading'
 }
 

И используйте этот компонент в своем основном компоненте

 {productList.map((val) => {
    return (
        <div key={val.id} className="product">
            <div className="item">
                <h1>Product title: {val.title}</h1>
                <h2>Price: {val.price}</h2>
                <h2>Quantity: {val.quantity}</h2>
                <ProductImage bannerImage={val.bannerImage} />
            </div>
        </div>
    ) 
})}
 

Комментарии:

1. Собираюсь попробовать это!