1

I currently have a method getReviewsLength() which will get the length of the reviews from firestore for each of the item in _favourites list. However, before the lengths are done adding into reviewsLength list, the method already triggers loadingComplete() method. Is there a way to make sure getReviewsLength() method finishes before triggering loadingComplete()?

I have try with async/await but I cant seem to make it work as i am unsure of where to put there.

getReviewsLength() {
    _favourites.forEach((shopname)  {
      firestore.collection('shops').doc(shopname['shopName']).collection('reviews').get()
          .then((value) {
          setState(() {
            int length = value.size;
            reviewsLength.add(length);
          });
      });
    });
    loadingComplete();
  }

  loadingComplete(){
    setState(() {
      loading = false;
    });
    print(reviewsLength);
  }
Roy
  • 137
  • 1
  • 1
  • 8
  • `getReviewsLength()` needs to be async. You need to remove the `forEach` and use a regular loop, then await each call to the `firestore.collection(...)` – smac89 Dec 14 '20 at 16:03
  • thank you @smac89. for loop works! – Roy Dec 14 '20 at 16:12

3 Answers3

1

as mentioned by @smac89, i changed to a for loop and it works.

Future<void> getReviewsLength() async {
    for (var shopname in _favourites) {
      dynamic snapshot = await firestore.collection('shops').doc(shopname['shopName']).collection('reviews').get();
          setState(() {
            int length = snapshot.size;//value.size;
            reviewsLength.add(length);

          });
    }
    loadingComplete();
    return;
  }

  void loadingComplete(){
    setState(() {
      loading = false;
    });
    print(reviewsLength);
  }
Roy
  • 137
  • 1
  • 1
  • 8
0

await lets you control the execution order and suits your specific scenario:

Future<void> getReviewsLength() async {
    Future.forEach(_favourites, (shopname) async {
         dynamic value = await firestore.collection('shops').doc(shopname['shopName']).collection('reviews').get();
          setState(() {
            int length = value.size;
            reviewsLength.add(length);
          });
    });
    loadingComplete();
    return;
}

void loadingComplete() {
 setState(() {
   loading = false;
 });
 print(reviewsLength);
}

Stefano Amorelli
  • 4,553
  • 3
  • 14
  • 30
0

Yes making you asynchronous will help here

to make a function asynchronous you need to use the keyword async between () and {} in a function and use await keyword in the place where you running the code

getReviewsLength() async {
    _favourites.forEach((shopname)  {
      await firestore.collection('shops').doc(shopname['shopName']).collection('reviews').get()
          .then((value) {
          setState(() {
            int length = value.size;
            reviewsLength.add(length);
          });
      });
    });
    loadingComplete();
  }

  loadingComplete(){
    setState(() {
      loading = false;
    });
    print(reviewsLength);
  }

I don't know whether the above code works or not as I am not sure about firestore but a basic example would be

function() async {
    await print('hello');
    print('world');
}

here the app won't print world until it prints hello, obviously there is no use of asynchronous function here but in the case of an API request it can used and in your case too.

So what you need to do is use the await keyword in right place where it makes request or adds it to reviewsLength

Regards,

Roshan

vIvId_gOat
  • 358
  • 2
  • 13