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?