0

I have 2 screens in my TabBarView that use the same data so instead of fetching it for each screen, I decided to make a shared data class with a StateNotifier to update both screens when the data is loaded. That looks like this:

class UsersDataProvider extends StateNotifier<Map<int, QueryDocumentSnapshot<Object?>>> {
  UsersDataProvider() : super({});

  Map usersMap = {};

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

    final QuerySnapshot result = await userRef.get();

    final docs = result.docs.asMap();

    usersMap = docs;
  }
}

class PostsDataProvider extends StateNotifier<Map<int, QueryDocumentSnapshot<Object?>>> {
  PostsDataProvider() : super({});

  final UsersDataProvider _usersDataProvider = UsersDataProvider();

  Map postsMap = {};

  Future<void> fetchPosts() async {
    _usersDataProvider.state.forEach((index, value) async {
      final postsRef = FirebaseFirestore.instance
          .collection('users')
          .doc(value.id)
          .collection('posts');
      final QuerySnapshot postsResult = await postsRef.get();
      final postDocs = postsResult.docs.asMap();

      postsMap = postDocs;
      state = postDocs;
    });
  }
}

In the TabBarView initState I call both of the fetch data functions. Then in each screen there's a function to turn the maps into posts and users which looks like this:

  final UsersDataProvider usersDataProvider = UsersDataProvider();
  final PostsDataProvider postsDataProvider = PostsDataProvider();

  Map docs = {};

  Map postDocs = {};

  final _searchController = TextEditingController();

  bool isSearch = false;

  List<UserSearchResult> usersList = [];
  List<Post> postsList = [];

  Future<void> fetchUsersAndPosts(bool initial) async {

    if (!initial) {
      usersDataProvider.fetchUsers();
      postsDataProvider.fetchPosts();
    }

    usersDataProvider.stream.listen((state) {
      print(state);
      setState(() {
        docs = state;
      });
      fetchUsersAndPosts(initial);
    });

    postsDataProvider.stream.listen((state) {
      print(state);
      setState(() {
        postDocs = state;
      });
      fetchUsersAndPosts(initial);
    });

    docs.forEach((index, value) async {

      List<Post> posts = [];

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

        posts.add(post);

        if (posts.length == postDocs.length) {
          setState(() {
            postsList = posts;
            postsList.sort((a, b) {
              return b.date.compareTo(a.date);
            });
          });
        }
      });

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

      Profile profile = Profile(profileInfo, posts);

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

      print(usersList.contains(user));

      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);
      });
    });
  }

  @override
  void initState() {
    fetchUsersAndPosts(true);
    super.initState();
  }

I don't see any reason for this not working, but it doesn't. Any ideas?

Globe
  • 514
  • 3
  • 17

0 Answers0