rahul  Kushwaha
rahul Kushwaha

Reputation: 2819

Not able to access the provider in flutter

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

Answers (3)

NBM
NBM

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

Ovidiu
Ovidiu

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

Er1
Er1

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

Related Questions