0

I am developing an application using react native by which user can find fishing boat providers from calendar. the user activity flow is the following;

  1. Select fishing methods(can be multiple).
  2. select date from calendar in which number of available fishing boats are shown.

In section number 2, I need to fetch data from firebase realtime database to get data like this.

"2021-01-31": Array [
 Object {
  "endTime": 1612044000000,
  "shipName": "ship nameA",
  "startTime": 1612044000000,
 },
 Object {
  "endTime": 1612044000000,
  "shipName": "ship nameB",
  "startTime": 1612044000000,
 },
],

and code is the following;

const getTourSchedules = async () => {
 const schedules = {};
 await selectedFishingMethods.map((item) => {
  const ref = `schedules/${item}`;
  Firebase.database().ref(ref).on('value', (snapShot) => {
    if (snapShot.exists) {
      snapShot.forEach((docs) => {
        const tour = docs.val().contents;
        const schedule = {
          endTime: tour.endTime,
          startTime: tour.startTime,
          shipName: tour.shipName,
        }
        if (!schedules[tour.date]) {
          schedules[tour.date] = [schedule];
        } else {
          schedules[tour.date].push(schedule);
        }
      })
    }
  })
 });
 console.log(schedules);
 setTours({ ...schedules });
};

The problem is the function above returns empty object and once the page is refreshed, the object is filled up with the data shown above.

Is there any way to wait until the outer map function finishes?

Thank you.

node -V: v14.7.0 expo -V: 3.28.5

2 Answers 2

1

Data is loaded from Firebase (and most modern cloud APIs) asynchronously. To allow the user to continue using the app while this happens, your main code continues executing. Then when the data is available, your callback is called.

This means that in your code the setTours({ ...schedules }); executes before schedules[tour.date].push(schedule); is ever called, meaning that you're always setting an empty schedules array to the state, which the app then renders.

Any code that needs data from the database, needs to be inside the callback or be called from there. So in your case, the simplest fix is:

const getTourSchedules = async () => {
 await selectedFishingMethods.map((item) => {
  const ref = `schedules/${item}`;
  Firebase.database().ref(ref).on('value', (snapShot) => {
    const schedules = {};
    if (snapShot.exists) {
      snapShot.forEach((docs) => {
        const tour = docs.val().contents;
        const schedule = {
          endTime: tour.endTime,
          startTime: tour.startTime,
          shipName: tour.shipName,
        }
        if (!schedules[tour.date]) {
          schedules[tour.date] = [schedule];
        } else {
          schedules[tour.date].push(schedule);
        }
      })
    }
    setTours({ ...schedules });
  })
 });
};
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your advice. I followed what you mentioned and solved the problem!
1

It looks calculations (loops) are not finished yet when you setState(...); Try adding await.

getTourSchedules = async () => {
    const schedules = {};
    await selectedFishingMethods.map((item) => {
        const ref = `schedules/${item}`;
        await Firebase.database().ref(ref).on('value', (snapShot) => {
            if (snapShot.exists) {
                snapShot.forEach((docs) => {
                    const tour = docs.val().contents;
                    const schedule = {
                        endTime: tour.endTime,
                        startTime: tour.startTime,
                        shipName: tour.shipName,
                    }
                    if (!schedules[tour.date]) {
                        schedules[tour.date] = [schedule];
                    } else {
                        schedules[tour.date].push(schedule);
                    }
                })
            }
        })
    });
    console.log(schedules);
    setTours({ ...schedules });
};

2 Comments

when I add await in front of Firebase.database()..., it gives me an error that saying 'await' is only allowed within async functions. hence I added async in map function like selectedFishingMethods.map(async (item) => ... However, the problem is still not solved..
Try replacing Map with For loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.