notabot
notabot

Reputation: 31

how can I add lazy loading to this list?

This is the how I fetch the posts in postList from firebase firestore, I need a function that works to get more posts on scroll. This next set of posts have to start after the last post that is displayed in this initial list and add to this list as the user scrolls as long as there are posts in the firestore.

class _FeedScreenState extends State<FeedScreen> {
  List<Post> _posts = [];
   ScrollController _controller = ScrollController();

  @override
  void initState() {
    super.initState();
    _setupFeed();
     _controller.addListener(_scrollListener);
  }

_scrollListener() {
    setState(() {
      if (_controller.position.atEdge) {
        if (_controller.position.pixels == 0) {


        } else {
          _getMore();

        }
      }
    });
  }
  _setupFeed() async {
    List<Post> posts = await DatabaseService.getFeedPosts(widget.currentUserId);
    setState(() {
      _posts = posts;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: Text(
          'New List',
          style: TextStyle(
            color: Colors.black,
            fontSize: 35.0,
          ),
        ),
      ),
      body: RefreshIndicator(
        onRefresh: () => _setupFeed(),
        child: ListView.builder(
          controller: _controller,
          itemCount: _posts.length,
          itemBuilder: (BuildContext context, int index) {
            Post post = _posts[index];
            return FutureBuilder(
              future: DatabaseService.getUserWithId(post.authorId),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  return SizedBox.shrink();
                }
                User author = snapshot.data;
                return PostView(
                  currentUserId: widget.currentUserId,
                  post: post,
                  author: author,
                );
              },
            );
          },
        ),
      ),
    );
  }
}

this is how i fetch the list of posts

static Future<List<Post>> getFeedPosts(String userId) async {
    QuerySnapshot feedSnapshot = await feedsRef
        .document(userId)
        .collection('userFeed')
        .orderBy('timestamp', descending: true)
        .limit(30)
        .getDocuments();
    List<Post> posts =
        feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
    return posts;
  }

Upvotes: 3

Views: 262

Answers (2)

na2axl
na2axl

Reputation: 1948

I think doing this will solve your issue:

You have to edit your getFeedPosts to collect your posts starting at a given index:

I'm not familiar to FireStore, I've found the startAt() method on docs

EDIT: I've misunderstood a Firestore concept, so I've change startAt() to startAfter() following Francisco Javier Snchez advice

static Future<List<Post>> getFeedPosts(String userId, TimeStamp start) async {
  QuerySnapshot feedSnapshot = await feedsRef
      .document(userId)
      .collection('userFeed')
      .orderBy('timestamp', descending: true)
      .startAfter(start)
      .limit(30)
      .getDocuments();
  List<Post> posts =
      feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
  return posts;
}

Now you can query it like this:

_getMore() async {
  // You have to give the timestamp of the last post here
  // Change this line by the right way...
  List<Post> posts = await DatabaseService.getFeedPosts(widget.currentUserId, _posts[_posts.length - 1].timestamp);
  setState(() {
    // Do += instead of =, += will add fetched posts to the current list, = will overwrite the whole list
    _posts += posts;
  });
}

Hope this will help!

Upvotes: 2

Francisco Javier Snchez
Francisco Javier Snchez

Reputation: 1003

na2axl answer was almost right. I will add here an explanation and example of how to use startAfter()

If you check the documentation on pagination, you will see that you need to use startAfter() referencing whatever filter you used. In your case you are ordering using timestamp so your next query should look like this:

static Future<List<Post>> getNextFeedPosts(String userId, TimeStamp timestamp) async {
    QuerySnapshot feedSnapshot = await feedsRef
        .document(userId)
        .collection('userFeed')
        .orderBy('timestamp', descending: true)
        //Here you need to let Firebase know which is the last document you fetched
        //using its timesTamp
        .startAfter(timestamp)
        .limit(30)
        .getDocuments();
    List<Post> posts =
        feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
    return posts;
  }

This means that your next query will still be ordered by a timestamp but the first document retrieved will be after the timestamp on startAfter

I hope this helps, however, you can check the documentation as there are other examples!

Upvotes: 2

Related Questions