0

I have 2 data provider classes that extend ChangeNotifier. Within each, there's a function to fetch data and at the end of them, I use notifyListeners() to notify the screens/listeners that the data changed. However, it seems that the listeners start getting notified endlessly instead of once and that creates a loop of reloading, circle indicators that don't go away, and a frozen screen. I don't get it.

Data providers:

class UsersDataProvider extends ChangeNotifier {
  UsersDataProvider() : super();

  static Map<int, QueryDocumentSnapshot<Object?>> usersMap = {};

  Future<void> fetchUsers() async {
    final userRef = FirebaseFirestore.instance.collection('users');

    final QuerySnapshot result = await userRef.get();

    final docs = result.docs.asMap();

    usersMap = docs;
    print(usersMap.length);
    notifyListeners();
  }
}

class PostsDataProvider extends ChangeNotifier {
  PostsDataProvider() : super();

  static Map<int, QueryDocumentSnapshot<Object?>> postsMap = {};

  Future<void> fetchPosts() async {

    UsersDataProvider.usersMap.forEach((index, resultValue) async {
      final postsRef = FirebaseFirestore.instance
          .collection('users')
          .doc(resultValue.id)
          .collection('posts');
      final QuerySnapshot postsResult = await postsRef.get();
      final postDocs = postsResult.docs.asMap();

      postsMap = postDocs;
      print('Post map: ${postsMap.length}');
      notifyListeners();
    });
  }
}

Add listeners and reload data:

Future<void> fetchUsersAndPosts(bool initial) async {

    if (!initial) {
      setState(() {
        postsLoading = true;
      });
      usersDataProvider.fetchUsers();
      postsDataProvider.fetchPosts();
    }

    if (initial) {
      usersDataProvider.addListener(() {
        print('changed');
        setState(() {
          fetchUsersAndPosts(false);
        });
      });
    }

    if (initial) {
      postsDataProvider.addListener(() {
        setState(() {
          fetchUsersAndPosts(false);
        });
      });
    }

    UsersDataProvider.usersMap.forEach((index, value) async {

      List<Post> posts = [];

      PostsDataProvider.postsMap.forEach((index, value) {
        final post = Post.fromJson(value.data() as Map<String, dynamic>);

        posts.add(post);

        setState(() {});

        if (posts.length == PostsDataProvider.postsMap.length) {
          setState(() {
            postsList = posts;
            postsList.sort((a, b) {
              return b.date.compareTo(a.date);
            });
            postsLoading = false;
          });
        }
      });

      final profileInfo =
      ProfileInfoObject.fromJson(value.data() as Map<String, dynamic>);

      Profile profile = Profile(profileInfo, postsList.where((p) => p.uid == value.id).toList());

      UserSearchResult user = (UserSearchResult(profile, value.id));

      if (usersList.where((u) => u.uid == user.uid).toList().isEmpty) {
        setState(() {
          usersList.add(user);
        });
      }
    });

    setState(() {
      postsList.sort((a, b) {
        return b.date.compareTo(a.date);
      });
    });
  }
Ken White
  • 123,280
  • 14
  • 225
  • 444
Globe
  • 514
  • 3
  • 17
  • use this listen: false where you're calling provider like Provider.of(context, listen: false).getData(); – Sumit Kumawat Sep 20 '22 at 00:56
  • I'm not understanding this. If you look at the `PostsDataProvider` that's just the name I gave it, it's actually a `ChangeNotifier` not a `Provider`. Maybe that's not what you meant and I'm misunderstanding but please look at the code snippets to understand how the code works. – Globe Sep 20 '22 at 01:15
  • I checked your code you're calling these two method so please try the below snippet to call Provider.of< UsersDataProvider >(context, listen: false). fetchUsersAndPosts(); Provider.of< PostsDataProvider >(context, listen: false). fetchPosts(); – Sumit Kumawat Sep 20 '22 at 01:25
  • I did try that when I saw your comment but it shows an error `Undefined name 'Provider'.` and I am not using a provider. Also, I do want it to listen because if the data changes I want the UI to reflect that. – Globe Sep 20 '22 at 01:31
  • OK, you're not using the provider. use the setState method to notify your data changes. – Sumit Kumawat Sep 20 '22 at 08:13

0 Answers0