Реагируйте: значение массива не определено в map () - PullRequest
0 голосов
/ 15 апреля 2020

Я создаю приложение реагирования, которое рендерит все продукты из firebase. Я получаю данные объекта и заменяю массив изображений новым массивом с правильной ссылкой. После этого я устанавливаю состояние с массивом объектов. Все идет хорошо, пока мне не нужно отобразить этот массив объектов и получить первое изображение из массива изображений из объекта. Я могу получить доступ ко всем данным из объекта, также я могу получить массив images , но когда я указал точное значение (images [0]) , я получу undefined

мой код

export default class List extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            loaded: false,
            productsArr: []
        }
    }

    componentDidMount() {
        this.setState({
            loaded: true
        })
        db.collection('products').get().then((list) => {
            let productsArr = []
            list.forEach((doc) => {
                let obj = doc.data();
                let imgArr =[];
                obj.images.forEach((img) => {
                    storageRef.child(`images/${img}`)
                    .getDownloadURL()
                    .then(url =>{
                        imgArr.push(url)
                    })
                    .catch(err => {
                        console.log('Getting image url ERROR', err)
                    })
                })
                const newObj = Object.assign(obj, {images: imgArr})
                productsArr.push(newObj)
            })
            this.setState({
                productsArr,
            })
        })
    }


    render() {
        return(
            <div>
                <Header />
                {this.state.loaded ? <Loading /> : null}
                <div>
                    {this.state.productsArr.map((product, i) => {
                        let arr = product.images
                        console.log(arr)
                        return (
                            <div key={i}>
                                <div>
                                    <div>
                                        <img src={product.images[0]}
                                            alt={product.category} 
                                        />
                                    </div>
                                </div>
                            </div>
                        )
                    })}
                </div>
                <Footer />
            </div>
        )
    }
}

как выглядит объект:

{
   category: "wooden",
   color: "black",
   height: "13",
   id: "103A220",
   images: ["https://firebasestorage.googleapis.com/v0/b/remini…=media&token=8668-deeac8dd21e0"],
   price: "4",
   productName: "Wood",
   warehouse: true,
   width: "14"
}

1 Ответ

0 голосов
/ 15 апреля 2020

Мое предположение: вызовы getDownloadURL() не разрешаются до того, как все foreach сделаны. Это приводит к обновлению состояния объектами, в основном содержащими пустые массивы images.

Чтобы обеспечить выполнение всего асинхронного потока c до того, как setState вы должны дождаться разрешения обещаний.

Попробуйте заменить componentDidUpdate() следующим:

componentDidMount() {
  db.collection("products")
    .get()
    .then((list) =>
      list.map((doc) => {
        // Get object
        const obj = doc.data();

        // Get all the images urls
        // This returns an array of promises
        const urlsPromises = obj.images.map((img) => {
          return storageRef.child(`images/${img}`).getDownloadURL();
        });

        // Pass the array of promises to Promise.all
        // and receive an array of urls that you assign to the obj.images key
        return Promise.all(urlsPromises)
          .then((urls) => Object.assign(obj, { images: urls }))
          .catch((err) => {
            console.log("Getting image url ERROR", err);
            // In case of error, keep the obj object as it is
            // Handle this as you which, this is an exemple
            return obj;
          });
      })
    )
    // Wait for the array of promises generated in the previous then
    .then(Promise.all)
    // Handle the array of altered obj
    .then((productArr) => this.setState({ loaded: true, productArr }))
    // Handle error as you like
    .catch(console.error);
}

И обновите это условие в вашем render() методе:

{this.state.loaded ? null : <Loading />}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...