Provider not found Flutter - flutter

I want to share some data across different widgets so I decided to use a ChangeNotifierProvider<Example> with its relative Consumer<Example>. I have already used Providers before but never in this way (in fact I got some errors).
ChangeNotifierProvider<Example> has been defined in menu page while Consumer<Example> in an other widget defined in menu too.
Menu page :
class Menu extends StatefulWidget {
//...SOme code
ChangeNotifierProvider<Example>(
create: (context) => Example(),
child: ShowMultipleAnswers()
//...some code
And now I would like to use Consumer<Example> inside ShowMultipleAnswers() widget consuming data created in menu like :
class ShowMultipleAnswers extends StatefulWidget {
//...some code
Widget build(BuildContext context) {
return Consumer<Example>(builder: (context, handler, child) {
//some code
But I got these errors :
Error: Could not find the correct Provider<Example> above this Consumer<Example> Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
consider using `builder` like so:
Make sure that Consumer<Example> is under your MultiProvider/Provider<Example>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
```
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
```
I think the most valid options are 2 :
- The provider you are trying to read is in a different route.
But I don't know because they should be in the same, I mean ShowMultipleAnswers() is the Provider child.
Or the second
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
In this case, following suggestions above, I should use a builder:(context){} instead of directly calling child : .. but I read that after provider 5 builder has been substituted by create so I'm confused.
If I'm using wrong widgets tell me please!

The error message exactly specifies and describe your error
ShowMultipleAnswers got built using Menu context which doesn't have the Example provider, thus it throws this error.
you can either use builder attribute instead of child or wrap your MaterialApp with the provider
your code should be something like this:
class Menu extends StatefulWidget {
//...SOme code
ChangeNotifierProvider<Example>(
create: (context) => Example(),
builder: (context) {
return ShowMultipleAnswers();
}
//...some code

I forgot to say that there was an other page between Menu and ShowMultipleAnswers, like a bridge between them so the real flow was :
Menu Page -> Bridge Page -> ShowMultipleAnswers Page.
I removed this Bridge Page and it worked! But I still don't understand why it didn't work, maybe because Bridge Page didn't have any references of its Provider?

Related

I have coded a simple responsive application. Though the code doesn't have any errors, when the application is ran it shows a build context error

This following was the error show in the app interface,
Error: Could not find the correct Provider above this MainScreen Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
-You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
-The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
-You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that MainScreen is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider(
create: () => Example().
// Will throw a ProviderNotFoundError, because context is associated
// to the widget that is the parent of Provider child: Text(context.watch()), ), } consider using builderlike so: Widget build(BuildContext context) { } return Provider( ), create: () => Example(). // we usebuilderto obtain a newBuildContext` that has access to the provider builder: (context) {
}
// No longer throws
return Text(context.watch()).
If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter
See also: https://flutter.dev/docs/testing/errors

Flutter: accessing providers from other providers

For my flutter project, I am using the following multiple providers below:
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<FirstProvider>(
create: (context) => FirstProvider(),
),
ChangeNotifierProvider<SecondProvider>(
create: (context) => SecondProvider(),
),
ChangeNotifierProvider<ThirdProvider>(
create: (context) => ThirdProvider(),
),
ChangeNotifierProvider<FourthProvider>(
create: (context) => FourthProvider(),
),
],
child: const MainApp(),
);
}
Because sometimes I need to either get data or call functions from different providers from another provider, I am using it like this:
//First Provider
class FirstProvider with ChangeNotifier {
void callFunctionFromSecondProvider({
required BuildContext context,
}) {
//Access the SecondProvider
final secondProvider= Provider.of<SecondProvider>(
context,
listen: false,
);
secondProvider.myFunction();
}
}
//Second Provider
class SecondProvider with ChangeNotifier {
bool _currentValue = true;
void myFunction(){
//Do something
}
}
The callFunctionFromSecondProvider()of the FirstProvider is called from a widget and it will call myFunction() successfully, most of times.
Depending on the complexity of the function, I am sometimes experiencing that I can't access the SecondProvider, presumably due to context being null, when the widget state changes.
I am reading some documents online regarding provider, and they are suggesting changenotifierproxyprovider for what I understood as 1 to 1 provider relationship.
However, in my case, one provider needs to be accessed by multiple providers and vice versa.
Question:
Is there a more appropriate way that I can approach my case where one provider can be accessed by multiple providers?
EDIT:
Accessing provider should also be able to access different variable values without creating a new instance.
Instead of passing context to the callFunctionFromSecondProvider function add the second provider as the parameter. So the function looks like the below.
Not sure this is the correct way of doing that but my context null issue was fixed this way.
void callFunctionFromSecondProvider({
required SecondProvider secondProvider,
}) {
secondProvider.myFunction();
}
}
Alright.
So it looks like Riverpod by the same author is the way to go as it addresses alot of flaws such as Provider being dependent on the widget tree, in my case, where the underlying issue came from.
—--------
For the time being, I still need to use the provider and for a quick and dirty solution, I am providing the context of not only the current widget that I am trying to access the provider, but also passing the parent context of the widget directly, so that in case a modal (for example) is closed, then any subsequent provider call can still be executed using the parent context.
Hope this helps.

Flutter: `Provider.of(context)` cannot be found when it is a `FutureProvider()`

I have a provider in my widget tree and I call Provider.of<List<...>>(context) to find it. If it is a provider of any type it works fine, however, as soon as change the provider from a Provider() (for example) to a FutureProvider() it doesn't work.
I haven't changed any widgets in the tree and haven't changed their position in the navigator. Provider.of() works fine but once I set it to be a FutureProvider() then it doesn't work.
Edit: My code looks something like this:
inside widget build:
return FutureProvider(
initialData: [],
create: (_) =>
DatabaseService(uid: _auth.getUser()!.uid).getJournalEntries(),
catchError: (context, error) {
print(error.toString());
},
...
}
Then one of the children is another widget and this is its build function:
List<JournalEntryData> entries =
Provider.of<List<JournalEntryData>>(context);
return ElevatedButton(
onPressed: () {
print(entries);
},
child: Text('print provider data'));
}
I get the following error:
Error: Could not find the correct Provider<List> above this TestButton Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that TestButton is under your MultiProvider/Provider<List>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
The problem is that there is a provider in the widget tree:
Replacing the FutureProvider() with any other type of provider makes it work, but I need a FutureProvider().
I didn't define the type of the FutureProvider() so it was dynamic but in my Provider.of() call I specified a type which caused the issue. Specifiying the type of the FutureProvider() should solve the issue.

Flutter: Connectivity Widget Wrapper Provider error

I've added ConnectivityWrapperWidget with my custom offlineWidget. I'm getting this error, while running the app
Error: Could not find the correct Provider above this ConnectivityWidgetWrapper Widget
This likely happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that ConnectivityWidgetWrapper is under your MultiProvider/Provider.
This usually happen when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
I don't get it. Can somebody explain, what is the issue
Try to use builder instead of child, as your error suggests. If it doesn't help, show some code.
While addig ConnectivityWrapper, if using custom offlineWidget(), then it was necesaary to add ConnectivityAppWrapper as a parent of MaterialApp.

Dart Provider: not available at the immediate child

#override
Widget build(BuildContext context) {
return BlocProvider<HomeBloc>(
create: (context) {
return HomeBloc(homeRepo: HomeRepository());
},
child: BlocProvider.of<HomeBloc>(context).state is HomeStateLoading
? CircularProgressIndicator()
: Container());
}
I am confused with the error:
BlocProvider.of() called with a context that does not contain a Bloc of type HomeBloc.
No ancestor could be found starting from the context that was passed to
BlocProvider.of<HomeBloc>().
Didn't I just create the HomeBloc at its immediate parent? What does it want?
You are using the context passed into the build method of your widget class to look for a parent BlocProvider. However, that context is the widget tree as far as your widget class sees it. Because of this, your BlocProvider.of is looking for a BlocProvider that is a parent of your widget class. If you want to get the provider that is the immediate parent, you need a new context object in which the BlocProvider is an ancestor in the widget tree. The easiest way to do this is with a Builder widget:
#override
Widget build(BuildContext context) {
return BlocProvider<HomeBloc>(
create: (context) {
return HomeBloc(homeRepo: HomeRepository());
},
child: Builder(
builder: (newContext) => BlocProvider.of<HomeBloc>(newContext).state is HomeStateLoading
? CircularProgressIndicator()
: Container(),
),
);
}
That being said, it's pretty redundant to create a provider and then immediately reverence the provider. Providers are for retrieving stuff further down the widget tree, not typically for immediate descendants. In this case, using a provider is overkill and there isn't really any reason to not just have the bloc be a field of your class and reference it directly.
From the documentation :
The easiest way to read a value is by using the static method
Provider.of(BuildContext context).
This method will look up in the widget tree starting from the widget
associated with the BuildContext passed and it will return the nearest
variable of type T found (or throw if nothing is found).
In your case it starts looking up the widget tree from your whole widget (associated to the BuildContext).
So you need to move your BlocProvider to be an ancestor of this widget.
If for some reason this is not possible, you can use Consumer, which allows obtaining a value from a provider when you don't have a BuildContext that is a descendant of the said provider.
Read https://pub.dev/documentation/provider/latest/provider/Consumer-class.html