Junaid Razaq
Junaid Razaq

Reputation: 251

How to wait for forEach loop to finish

I am having an issue where I am trying to fetch data. Unfortunately, when I console log the result, on the initial page load, the data is empty. When I re render the component however, I receive the data successfully.

This is what I currently have:

function Followers({
   urlname,
    navigation
}) {
    const [followersData, setfollowersData] = useState(null)

    useEffect(() => {
         // Fetch Followers data
         const dataRef = firestore().collection('usernames')
     
            dataRef.doc(urlname)
            .collection('Following')
            .get()
            .then((docSnapshot) => {
            let items = []

            docSnapshot.forEach(doc => {
                let item = {}

                // Store followers, display name and follows info
                dataRef
                .doc(doc.id)
               .get()
                .then((followerDoc) => {
                    const data = followerDoc.data();
                    item.profileName = doc.id
                    item.displayName = data.userName
                    item.followerCount = data.followers
                    item.followingCount = data.following
                })

                items.push(item)
            })
            setfollowersData(items)
            })

    }, [])

return (
    <>
        {console.log('followersData', followersData)}
    </>
)
}

export default Followers

The console log I receive on the first page load is:

followersData null
followersData [{}, {}, {], {}]
followersData [{}, {}, {], {}]

When the component renders again, I receive this in the console log:

followersData [all my data in 4 different objects gets logged]

Upvotes: 2

Views: 1134

Answers (2)

Alex Chuev
Alex Chuev

Reputation: 713

William's solution is good, but as an option is to wait all the responses and update the state once.

const promises = [];

docSnapshot.forEach((doc) => {
  const promise = dataRef
    .doc(doc.id)
    .get()
    .then((followerDoc) => {
      const data = followerDoc.data()

      return {
        profileName: doc.id,
        displayName: data.userName,
        followerCount: data.followers,
        followingCount: data.following,
      }
    });

   promises.push(promise);
})

Promise.all(promises).then(setfollowersData);

Upvotes: 1

wangdev87
wangdev87

Reputation: 8751

call setfollwersData() separately for each item using prev state and set initial state empty array.

function Followers({
   urlname,
    navigation
}) {
    const [followersData, setfollowersData] = useState([])

    useEffect(() => {
         // Fetch Followers data
         const dataRef = firestore().collection('usernames')
     
            dataRef.doc(urlname)
            .collection('Following')
            .get()
            .then((docSnapshot) => {

            docSnapshot.forEach(doc => {
                let item = {}

                // Store followers, display name and follows info
                dataRef
                .doc(doc.id)
               .get()
                .then((followerDoc) => {
                    const data = followerDoc.data();
                    item.profileName = doc.id
                    item.displayName = data.userName
                    item.followerCount = data.followers
                    item.followingCount = data.following
                    setfollowersData(prev => [...prev,item])
                })

            })
        })

    }, [])

return (
    <>
        {console.log('followersData', followersData)}
    </>
)
}

export default Followers

Upvotes: 1

Related Questions