Use case of the app:
main.dart:
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => RandomUser(),
),
ChangeNotifierProxyProvider<RandomUser, FavoriteList>(
create: (BuildContext ctx) => FavoriteList(ctx.read<RandomUser>()),
update: (_, RandomUser user, __) => FavoriteList(user),
),
RandomUser provider:
class RandomUser extends ChangeNotifier {
final apiUsers = UsersApi();
UserModel? _profile;
String? _userId;
RandomUser() {
fetchUser();
}
Future<void> fetchUser() async {
await apiUsers
.apiGetUser()
.then((user) => {
_profile = user,
_userId = chosenUserId,
})
.catchError((e) {
print("error: $e");
});
notifyListeners();
}
UserModel get profile => _profile;
String get chosenUserId => _userId;
}
FavoriteList provider:
class FavoriteList extends ChangeNotifier {
final RandomUser _user;
final _apiFavoriteList = FavoriteListApi();
List<FavoriteListModel> _favoriteList = <FavoriteListModel>[];
FavoriteList(this._user) {
fetchFavoriteList(_user.chosenUserId);
}
Future<void> fetchFavoriteList(String userId) async {
await _apiFavoriteList
.apiGetFavoriteList(userId)
.then((favoriteList) => {
_favoriteList = favoriteList,
})
.catchError((e) {
print("error: $e");
});
notifyListeners();
}
List<FavoriteListModel> get favoriteList => this._favoriteList;
}
So as you can see, the FavoriteList provider
needs the RandomUser provider
, to retrieve the getter value chosenUserId
When I launch the App, I get right away the error "Null check operator used on a null value"
on the getter chosenUserId
and in the main.dart
where I call "create"
of the ProxyProvider
What am I doing wrong?
Shouldn't the ProxyProvider
first initialized the first Provider
, so all the values I need are available?
The issue is that RandomUser.fetchUser()
has not completed before FavoriteList
is created. You should code allowing for this situation, e.g. in RandomUser
:
String? get chosenUserId => _userId;
and in FavoriteList
:
final? RandomUser _user;
FavoriteList(this._user) {
if (_user != null && _user?.chosenUserId != null) {
fetchFavoriteList(_user.chosenUserId);
}
}
String? get chosenUserId => _user?.chosenUserId;
When fetchUser()
completes then FavoriteList
will be updated.
Your UI will have to cope with the (temporary) missing data, of course.
BTW the documentation for ChangeNotifierProxyProvider suggests that you should structure your code like this:
ChangeNotifierProxyProvider<MyModel, MyChangeNotifier>(
create: (_) => MyChangeNotifier(),
update: (_, myModel, myNotifier) => myNotifier
..update(myModel),
child: ...
);
In that situation, if MyModel were to update, then MyChangeNotifier will be able to update accordingly. Notice how MyChangeNotifier doesn't receive MyModel in its constructor anymore. It is now passed through a custom setter/method instead.