Reputation: 2819
I have a simple provider class:-
class DataProvider with ChangeNotifier {
int count;
void updateCount() {
count = count + 1;
notifyListeners();
}
}
I am attaching this provider to the following class:-
class MyWidget extends StatelessWidget{
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => DataProvider(),
child: Scaffold(
body: raisedButton(
onPressed: () {
Provider.of<DataProvider>(context).updateCount();
}
child: Text("Click!")
),
),
),
}
and its Giving me the following error:-
I/flutter (32011): Error: Could not find the correct Provider<DataProvider> above this MyWidget
Widget
I/flutter (32011): To fix, please:
I/flutter (32011): * Ensure the Provider<DataProvider> is an ancestor to this MyWidget Widget
I/flutter (32011): * Provide types to Provider<DataProvider>
I/flutter (32011): * Provide types to Consumer<DataProvider>
I/flutter (32011): * Provide types to Provider.of<DataProvider>()
I/flutter (32011): * Ensure the correct `context` is being used.
What could be the reason for this?
Edit:-
It's working fine when I access the provider from any child widget of the widget where I have defined. ChangeNotifierProvider
.
Upvotes: 0
Views: 1756
Reputation: 1036
Having the Scaffold inside the Builder widget helped me to resolve the issue with Provider
Widget build(BuildContext context) {
return ChangeNotifierProvider<StatusViewModel>(
create: (context) => StatusViewModel(),
child: Builder(
builder: (context){
return Scaffold(
appBar: AppBar(
title: Text("this is appbar"),
),
);
},
),
);}
Upvotes: 0
Reputation: 8714
This is because you are calling Provider.of<DataProvider>(context).updateCount()
using the wrong context
. You are using the context
provided by the build
method, which is higher up the hierarchy than the Provider you are trying to access. You need to use a context
that belongs to a descendant (lower down the hierarchy) of the Provider.
Wrap your Scaffold
in a Builder
widget, which exposes a new context
at that level in the widget hierarchy, and use that context instead.
You could also use a Consumer
, although it would not be optimal in your example because Consumer
will rebuild every time notifyListeners()
is called in the Provider, which would be redundant because your UI does not change.
Upvotes: 2
Reputation: 2758
You need to wrap your raisedButton
in a Consumer
.
The Consumer widget has two main purposes:
It allows obtaining a value from a provider when we don't have a BuildContext that is a descendant of said provider, and therefore cannot use Provider.of. This scenario typically happens when the widget that creates the provider is also one of its consumers, like in the following example:
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => Foo(), child: Text(Provider.of<Foo>(context).value), ); }
This example will throw a ProviderNotFoundException, because Provider.of is called with a BuildContext that is an ancestor of the provider.
Instead, we can use the Consumer widget, that will call Provider.of with its own BuildContext.
Using Consumer, the previous example will become:
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => Foo(), child: Consumer<Foo>( builder: (_, foo, __) => Text(foo.value), }, ); }
This won't throw a ProviderNotFoundException and will correctly build the Text. It will also update the Text whenever the value foo changes.
See: https://pub.dev/documentation/provider/latest/provider/Consumer-class.html
Upvotes: 1