Reputation: 2890
I am using the provider libarary for my state management and everything works fine up until this point. However, I have noticed that when calling notifyListeners
from another screen (or a popup like showModalBottomSheet
) my UI will not be notified.
The method I am using in the provider
looks something like this and adds an item to a ListView:
void addEntry(http.Response response) {
Group group = Group.fromJson(jsonDecode(response.body));
groups.add(group);
notifyListeners();
}
As for the UI the entire Screen is wrapped in a Consumer
. Calling this method from a button in the screen works fine and the list is updated. Calling this method from a popup created with showModalBottomSheet
does not update the UI.
How do I ensure the UI is notified of the changes?
Update #1:
I have a button that calls showModalBottomSheet
like this:
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
},
);
So it creates a popup with a separate widget. That separate widget in turn does this when another button is pressed:
widget.model.createGroup(name, icon);
This method eventually calls addEntry
. As I said this works perfectly fine without a popup but does not work at all in the popup :/
Upvotes: 1
Views: 1966
Reputation: 2030
Pop-ups like bottomsheets are most likely opened from the root navigator and hence provides a different context and if your provider is not created above the root Navigator i.e above the MaterialApp, it will cause this issue.
The context
that is coming from the builder
of the showModalBottomSheet
is not where your Provider is created.
There are 2 solutions I can think of:
showModalBottomSheet
, you can create a reference to the Provider and then pass that to the AddWidget.var provider = Provider.of<GroupsProvider>(context, listen:false);
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: provider),
);
},
);
ChangeNotifierProvider.value
and wrap the widget in the builder with it.showModalBottomSheet<void>(
...
context: context,
builder: (_) {
return ChangeNotifierProvider.value(
value: Provider.of<GroupsProvider>(context, listen:false),
builder: (context, _) =>
Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
);
},
);
(2) ensures that the widget tree below it will have access to the same Provider instance. For new screens, you can do :
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(...),
),
);
Looking at the widget inspector in debug mode will help you understand better
Upvotes: 4