简体   繁体   中英

React map function does not execute when the component is rendered

As you can see below in the dev tools screen shot, the child element does have props. My issue is I cannot get them to appear in the DOM when the component is first rendered. I have to click on the Link element again to re-render the component and only then does the map function work correctly (second screen shot). Another thing is I am using the same code in another component and it works fine. Help!

import React, { useState, useEffect } from 'react'
import firebase from 'firebase';
import NewsLetterListChildComponent from './children/NewsLetterListChildComponent';
import LoadingComponent from '../Loading/LoadingComponent';

function PublicNewsLetterListComponent({ user }) {
    const [ newsLetters, setNewsLetters ] = useState([]);
    const [ loading, setLoading ] = useState(false);
    const [ errors, setErrors ] = useState(false);

    useEffect(() => {
        let requestCancelled = false;

        const getNewsLetters = () => {
            setLoading(true);
            let newsLetterArray = [];
            firebase
                    .firestore()
                    .collection('newsLetters')
                    .get()
                    .then((querySnapshot) => {
                        querySnapshot.forEach((doc) => {
                        const listRef = firebase.storage().ref().child('newsLetterImagesRef/' + doc.id);
                        listRef
                            .getDownloadURL()
                            .then(url => {
                                newsLetterArray.push({ id: doc.id, data: doc.data(), image: url });
                            })
                            .catch(error => console.log(error))
                });
            });

            setNewsLetters(newsLetterArray);
            setLoading(false);
        };

        getNewsLetters();

         return () => {
            requestCancelled = true;
         };
    }, []);
    
    const renderContent = () => {
        if(loading) {
            return <LoadingComponent />
        } else {
            return <NewsLetterListChildComponent newsLetters={newsLetters} /> 
        }
    }
    return renderContent();

    
}

export default PublicNewsLetterListComponent
import React from 'react';
import { ListGroup, ListGroupItem, Row, Col } from 'reactstrap';

function NewsLetterListChildComponent({ newsLetters }) {
    return (
    <div>
        <Row>
            <Col md={{size: 6, offset: 3}}>
                <ListGroup>
                {newsLetters.map((item, index) => {
                    return (
                        <ListGroupItem key={index} className="m-1" ><h1>{item.data.title} </h1><img src={item.image} alt={item.data.title} className="thumb-size img-thumbnail float-right" /></ListGroupItem>
                    );
                })}
                </ListGroup>
            </Col>
        </Row>
    </div>
    )
}

export default NewsLetterListChildComponent;

Initial render and the list group is empty

初始渲染和列表组为空

after the re-render and now the list group is populated

重新渲染后,现在列表组已填充

You need to call setNewsLetters when the data is resolved:

const getNewsLetters = async () => {
  setLoading(true);
  
  try {
    const newsLetters = await firebase
      .firestore()
      .collection("newsLetters")
      .get();
  
    const data = await Promise.all(
      newsLetters.docs.map(async (doc) => {
        const url = await firebase
          .storage()
          .ref()
          .child("newsLetterImagesRef/" + doc.id)
          .getDownloadURL();

        return {
          id: doc.id,
          data: doc.data(),
          image: url,
        };
      })
    );
    
    setNewsLetters(data);
  } catch (error) {
    console.log(error);
  } finally {
    setLoading(false);
  }
};

The useEffect code contains an async request and you are trying to update an array of newsLetters in state even before it will be fetched. Make use of Promise.all and update the data when it is available

useEffect(() => {
    let requestCancelled = false;

    const getNewsLetters = () => {
        setLoading(true);
        firebase
                .firestore()
                .collection('newsLetters')
                .get()
                .then((querySnapshot) => {
                    const promises = querySnapshot.map((doc) => {
                    const listRef = firebase.storage().ref().child('newsLetterImagesRef/' + doc.id);
                    return listRef
                        .getDownloadURL()
                        .then(url => {
                            return { id: doc.id, data: doc.data(), image: url };
                        })
                        .catch(error => console.log(error))
                    Promise.all(promises).then(newsLetterArray => { setNewsLetters(newsLetterArray);})
            });
        });

        
        setLoading(false);
    };

    getNewsLetters();

     return () => {
        requestCancelled = true;
     };
}, []);

If you check newletters with if, your problem will most likely be resolved.

review for detail: https://www.debuggr.io/react-map-of-undefined/

 if (newLetters){ newLetters.map(item=>...) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM