My app starts with retrieving data that is important throughout the flow of the app mainContent
. Most of this data is static
Widget stackPages(WidgetRef ref) {
AsyncValue<Map<String, Object>> mainContent = ref.watch(mainContentFutureProvider);
return mainContent.when(
loading: () => Center(child: CircularProgressIndicator()),
error: (e, st) => Center(child: Text("Error: " + e.toString() + " " + st.toString())),
data: (content) {
return Stack(
children: [
_buildOffstageNavigator(ref, "Home", content),
_buildOffstageNavigator(ref, "Page1", content),
_buildOffstageNavigator(ref, "Page2", content),
_buildOffstageNavigator(ref, "Page3", content)
],
);
},
);
}
final mainContentFutureProvider= FutureProvider<Map<String, Object>>((ref) async {
List response = await Future.wait([
DataController.userInfoDB.getUsers(),
DataController.userInfoDB.getAnotherList(),
DataController.userInfoDB.getAnotherList,
]);
return {
"users": response[0],
"some_list": response[1],
"some_list": response[2],
};
},
);
class User{
String id;
String email;
List<Vehicle> vehicles = [];
User(this.email, this.vehicles);
User.fromJson(Map<String, dynamic> json)
: id = json['id'],
displayName = json['display_name'],
}
in the garage screen of the app the user can add or remove vehicles. When a user adds or removes a vehicle this affects the entire flow of the app. So this User
needs to have its Notifier
class
class CurrentUserNotifier extends StateNotifier<User> {
final User user;
CurrentUserNotifier(this.user) : super(null);
void addUserVehicle(Vehicle vehicle) {
state..vehicles.add(vehicle);
}
void removeUserVehicle(int vehicleId) {
state..vehicles.removeWhere((v) => v.id == vehicleId);
}
}
final currentUserProvider = StateNotifierProvider.family<CurrentUserNotifier, User, User>((ref, user) {
return CurrentUserNotifier(user);
});
Currently I am retrieving a List<User>
and want only to have the current user to be coming from a provider
in my app. As you see I have made a .family
from StateNotifierProvider
so I can perform the following thing:
final mainContentFutureProvider= FutureProvider<Map<String, Object>>((ref) async {
List response = await Future.wait([
DataController.userInfoDB.getUsers(),
DataController.userInfoDB.getAnotherList(),
DataController.userInfoDB.getAnotherList,
]);
---> currentUserProvider(response[0].first);
return {
"users": response[0],
"some_list": response[1],
"some_list": response[2],
};
},
);
But for any page that deals with my User
object it needs to pass through the user
object as parameter to my currentUserProvider
like:
press: () async {
ref.read(currentUserProvider(user).notifier).addUserVehicle(vehicle);
}
I want the provider just set the value of the StateNotifierProvider
once, am I making a pattern/flow mistake here?
Try this:
Have your CurrentUserNotifier
like so.
final currentUserProvider = StateNotifierProvider<CurrentUserNotifier, User>((ref) {
return CurrentUserNotifier();
});
class CurrentUserNotifier extends StateNotifier<User?> {
CurrentUserNotifier() : super(null);
void setUser(User user){
state = user;
}
void addUserVehicle(Vehicle vehicle) {
state = state..vehicles.add(vehicle);
}
void removeUserVehicle(int vehicleId) {
state = state..vehicles.removeWhere((v) => v.id == vehicleId);
}
}
Then set the user
like so:
final mainContentFutureProvider= FutureProvider<Map<String, Object>>((ref) async {
List response = await Future.wait([
DataController.userInfoDB.getUsers(),
DataController.userInfoDB.getAnotherList(),
DataController.userInfoDB.getAnotherList,
]);
ref.read(currentUserProvider.notifier).setUser(response[0].first);
return {
"users": response[0],
"some_list": response[1],
"some_list": response[2],
};
},
);
Then you can do:
press: () async {
ref.read(currentUserProvider.notifier).addUserVehicle(vehicle);
}