简体   繁体   中英

Flutter How to pass in documents.length from Firestore in another method?

I have a method which takes an int value, which is supposed to be the value of the length of an array field in a document in a collection in Cloud Firestore .

I'm very new to both Flutter and especially Firestore, and I figure it has something to do with how futures, queries and streams works, but I can't seem to understand it correctly.

This is what I'm trying to achieve:

class UserBookmarksSection extends StatefulWidget {
  @override
  _UserBookmarksSectionState createState() => _UserBookmarksSectionState();
}

class _UserBookmarksSectionState extends State<UserBookmarksSection> {  
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,      
      children: <Widget>[
        HeadlineItem(title: "Your bookmarks"), 
        StreamBuilder(
          stream: Firestore.instance.collection("brites").snapshots(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) return const Text("Loading...");
            return Column(
              children: populateBriteList(snapshot, x, true), //Here I want to pass in the length of the array in firestore into x
            );
          }
        ),
      ],
    );
  }
}

Basically I've tried to create a method which returns a Future<int> and tried to pass that, but that didn't work because a Future<int> isn't the same type as int . That I understand, but the solution is not clear to me.

I'm not sure the relationship between brites and bookmarks- that is, which you expect to change more often. I'm going to assume that the bookmarks isn't changing once the user opens the bookmarks section.

If that is the case you can retrieve the bookmarks length value in initState. You will override the state class's initState() method, and then call an async method which retrieves the value from the database. (init state can't be async itself). Once the value is retrieved, you can then call setState() to update the widget with the value of bookmarks set as an int.

Might look something like this:

class UserBookmarksSection extends StatefulWidget {
  @override
  _UserBookmarksSectionState createState() => _UserBookmarksSectionState();
}

class _UserBookmarksSectionState extends State<UserBookmarksSection> {  
  int bookmarksLength;

  @override
  void initState(){
    super.initState();
    getBookmarksLength();
  }

  Future<void> getBookmarksLength() async {
    bookmarksLength = await getArrayLength(id);
    setState((){});
  }

  @override
  Widget build(BuildContext context) {
    if(bookmarksLength == null) return CircularProgressIndicator();
    else return Column(
      crossAxisAlignment: CrossAxisAlignment.start,      
      children: <Widget>[
        HeadlineItem(title: "Your bookmarks"), 
        StreamBuilder(
          stream: Firestore.instance.collection("brites").snapshots(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) return const Text("Loading...");
            return Column(
              children: populateBriteList(snapshot, bookmarksLength, true), 
            );
          }
        ),
      ],
    );
  }
}


Firestore firestore = Firestore.instance;

Future<int> getArrayLength(String documentId) async {
  DocumentSnapshot snapshot = await firestore.collection('collection').document(documentId).get();
  return snapshot.data['array'].length;
}

A more robust solution might be to have a separate class that handles both listening to the stream and retrieving the length of the array, and then combining all of the information you're going to display into some abstract data type which you put into a separate stream you specify that is specifically for the UI to listen to.

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