Toesmash
Toesmash

Reputation: 327

Firebase - waiting for data from async database call

I am trying to fetch some data from firebase with 2 database calls. My strategy to get accounts only for 1 user is as follows:

My firebase structure look like this.

enter image description here

My problem is that the second fetch call always finishes last.

export const fetchAccounts = () => {
   return (dispatch, getState) => {
      const accounts = [];
      const uid = getState().auth.uid;

      return database.ref(`users/${uid}/accounts`).once('value').then((snapshot) => {
         snapshot.forEach((element) => {
            database.ref(`accounts/${element.key}`).once('value').then((snapshot) => {
               accounts.push(snapshot.val());
               console.log('snapshot: ', accounts);
            })
         });
         console.log('Acc 1:', accounts);
      }).then(() => {
         console.log('Acc 2:', accounts)
      })

      // dispatch call with full array
   }
};

enter image description here

I am calling action from main file

  reduxStore.dispatch(fetchAccounts()).then(()=>{
     renderApp();
  });

Is it possible to wait for both database calls to finish and then call dispatch function with fully populated array? Appreciate any idea.

Upvotes: 0

Views: 1733

Answers (1)

charlietfl
charlietfl

Reputation: 171679

Your first then() doesn't return anything so the second then() will fire immediately which is what you are seeing in the console. The loop of requests however are asynchronous and haven't completed yet

Create an array of promises and use Promise.all() so the second then() won't fire until the requests in the loop all complete.

export const fetchAccounts = () => {
   return (dispatch, getState) => {
      const accounts = [];
      const uid = getState().auth.uid;

      return database.ref(`users/${uid}/accounts`).once('value').then((snapshot) => {
         const accountPromises =[];// array to store promises

         snapshot.forEach((element) => {
            // reference promise to pass into array
            const request = database.ref(`accounts/${element.key}`).once('value').then((snapshot) => {
               accounts.push(snapshot.val());
               console.log('snapshot: ', accounts);
            });
            // push request promise to array
            accountPromises.push(request)

         });
         console.log('Acc 1:', accounts);// accounts should still be empty here since requests are in progress
         // return promise that doesn't resolve until all requests completed
         return Promise.all(accountPromises);
      }).then(() => {
         // shouldn't fire until all the above requests have completed
         console.log('Acc 2:', accounts);
         return accounts // return array to use in next `then()`
      })

      // dispatch call with full array
   }
};

Upvotes: 2

Related Questions