Building off class that indirectly extends from StateNotifier in StateNotifierProvider doesn't work
I will have abstract DogNotifier extends StateNotifier<DogInfo> and some children notifiers ShibaNotifier, that extend it.
However, in the UI, not sure the best way to handle:
I was thinking of having another provider aka KennelNotifier which would keep track of which Dog we are looking at in a DogNotifier whichDog() method.
So that I can reuse the UI like:
ref.watch(ref.read(kennelNotifier).whichDog))
But this has to be wrong or is it ok? Wondering how I can reuse my UI code for a Dog in a conditional way like this as I still would like a ShibaNotifier and a LabradorNotifier etc.
Thank you.
So,
it probably is possible to get providers dynamically: https://github.com/hunterpp/riverpod_child_provider/blob/ff30883e5c502b5e821f3c4bb8cc4a93dec21d65/lib/main.dart#L53
but it involved multiple calls to ref.watch:
Text(ref.watch(ref.watch(kennelProvider).dog.notifier).produce()),
And not sure that is idiomatic and feels risky.
What I settled on was using family:
https://github.com/hunterpp/riverpod_child_provider/blob/main/lib/main.dart
And explicitly passing a type to get the correct child notifier
Text(ref.watch(dogProvider(DogType.pittie).notifier).produce()),
Text(ref.watch(dogProvider(DogType.shiba).notifier).produce()),
Assume that class A is arbitrarily rooted, and its children are classes B, C, and D.
(Not all classes are in the same hierarchy)
When I use BlocConsumer or BlocBuilder in class D, I get an error.
I just want to reuse the Bloc state used in class A and class B.
is there any solutions? thanks
--UPDATE
I am talking about this https://github.com/felangel/bloc/issues/74
Is there any way other than passing it as navigator argument to class one by one?
Note: I assume you are using the flutter_bloc library, but the concept is the same even though you are not.
The BLoC you want to access must be provided ABOVE all the screens/pages you want to access this BLoC in. The simplest solution to your problem would be wrapping your root Widget (probably MaterialApp) with BlocProvider:
runApp(
BlocProvider<YourBloc>(
create: (_) => YourBloc(), // create your BLoC here
child: MaterialApp(...),
),
);
For more info, I would recommend watching this video: https://www.youtube.com/watch?v=laqnY0NjU3M
introduce blocprovider on main myapp page and use it on other pages
Is it bad practice to create multiple instances of the same bloc/cubits in the tree? I'm creating an instance of the cubit and using it in a few locations in the tree-like so.
BlocBuilder<BlocA, BlocAState>(
cubit: blocA, // provide the local cubit instance
builder: (context, state) {
// return widget here based on BlocA's state
}
)
... but the blocs are scoped to a single widget with this method. I'm using this technique 3 times in the widget tree (splitting up my widgets into different classes). My console is spitting out several instances of the bloc in question from the BlocObserver. The blocs "work" but I'm suspicious I'm going about things the incorrect way...
Seems like you misunderstood the core concept of providing a bloc instance to your widget tree. You need BlocBuilder to set up the BuildContext for your widgets, that depend on bloc, and to minimize the scope of widgets, that will be marked for rebuild on bloc changes.
Yes this is very bad practice to have multiple bloc instances as it will almost nullify its usefulness to your app. To provide a single instance to your widgets use BlocProvider or BlocProvider.value, more about it you can check here or here
I'm still wrapping my head around state-management techniques in flutter and am a bit confused about when and why to use Provider.of<X> vs. Consumer<X>. I understand (I think) from the documentation that when choosing between these two you would use Provider.of when we want access to the data, but you don't need the UI to change. So the following (taken from the docs) gets access to the data and updates the UI on new events:
return HumongousWidget(
// ...
child: AnotherMonstrousWidget(// <- This widget will rebuild on new data events
// ...
child: Consumer<CartModel>(
builder: (context, cart, child) {
return Text('Total price: ${cart.totalPrice}');
},
),
),
);
Whereas, where we only need the data on don't want to rebuild with UI, we'd use Provider.of<X> with the listen parameter set to false, as below:
Provider.of<CartModel>(context, listen: false).add(item); \\Widget won't rebuild
However, listen isn't required and so the following will run too:
Provider.of<CartModel>(context).add(item); \\listener optional
So this brings me to a few questions:
Is this the correct way to distinguish Provider.of<X> and Consumer<X>. Former doesn't update UI, latter does?
If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?
Why have Provider.of with the option to rebuild the UI at all when we have Consumer?
It doesn't matter. But to explain things rapidly:
Provider.of is the only way to obtain and listen to an object.
Consumer, Selector, and all the *ProxyProvider calls Provider.of to work.
Provider.of vs Consumer is a matter of personal preference. But there's a few arguments for both
Provider.of
can be called in all the widgets lifecycle, including click handlers and didChangeDependencies
doesn't increase the indentation
Consumer
allows more granular widgets rebuilds
solves most BuildContext misuse
Provider.of<>
applying provider, whole widget will rebuild if listen true.
Consumer<>
using consumer only specifically allowed widget will rebuild.
For your questions:
Is this the correct way to distinguish Provider.of<X> and Consumer<X>. Former doesn't update UI, latter does?
Provider.of<X> depends on value of listen to trigger a new State.build to widgets and State.didChangeDependencies for StatefulWidget.
Consumer<X> always update UI, as it uses Provider.of<T>(context), where listen is true. See full source here.
If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?
Default value is true, means will trigger a new State.build to widgets and State.didChangeDependencies for StatefulWidget. See full source here.
static T of<T>(BuildContext context, {bool listen = true}).
Why have Provider.of with the option to rebuild the UI at all when we have Consumer?
Pretty much covered by Rémi Rousselet's answer.
There should not be any performance concern by using it, moreover, we should use consumers if we want to change some specific widget only on screen. This is the best approach I can say in terms of coding practice.
return Container(
// ...
child: Consumer<PersonModel>(
builder: (context, person, child) {
return Text('Name: ${person.name}');
},
),
);
Like in the above example, we are only required to update the value of the Single Text Widget so add consumers there instead of Provider which is accessible to other widgets as well.
Note: Consumer or Provider update the only reference of your instance which widgets are using, if some widgets are not using then it will not re-drawn.
The widget Consumer doesn't do any fancy work. It just calls Provider.of in a new widget, and delegate its build implementation to [builder].
It's just syntactic sugar for Provider.of but the funny thing is I think Provider.of is simpler to use.
Look at this article for more clearance
https://blog.codemagic.io/flutter-tutorial-provider/
We have 3 things to understand here.
When you wrap Provider around a widget it sets up a reference to a widget tree and a variable whose changes you want to refer to.
using Provider.of(context) you can get access to the variable you want to monitor and make changes in it.
Provider.of(context) with and without listen gives you a reference to the above-declared Provider object and a widget tree where it can be accessed from. But as said by others, it rebuild the whole widget tree it sits on top of when listen is not false.
In the end, you can use consumer to monitor any changes that happened using the above step
The consumer acts like a more granular listener and be applied to a fixed widget to help avoid unnecessary rebuilds.
it's just a personal preference and depends on how you understand and use provider.
so the way i think of provider is it's just an object that is providing a ChangeNotifier Object that has Code and Data down the widget Tree.
So,I use :
Consumer<T>
When i want to listen to changes in Data and update/rebuild my UI according to those changes.
Provider.of<T>
When i just want to call the Code. with the listen parameter set to false.
if your problem is to know what the difference is, here is a track
Consumer
reload consumer-only child widgets
Provider.of (with listen true)
reload from the last buildcontext found in the tree
actually in a simple example
exemple1 provider.of
in exemple1 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)
with 'provider.of' flutter rebuild at the first Buildcontext below #override
that mean the totality of tree are rebuild
exemple2 consumer
in exemple2 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)but with consumer only sélectionned widget are rebuild
that mean one widget are rebuild the other widget doesn't "move"
I hope I could help you
From the docs I understood that one can call addListener() on a ChangeNotifier instance to add a custom listener to the stack.
This method accepts a callback with zero arguments (according to notifyListeners()), e.g.:
class MyClass extends ChangeNotifier {
MyClass() {
addListener(() {
// ...
});
}
}
From within the callback, how does one find out what properties or parts of MyClass have been changed?
ChangeNotifier does not have such capabilities inherently. You will have to implement your own logic. Specifically, you either have access to all of the properties of your ChangeNotifier implementation because you add the listener in its scope or you have access to it because you have a reference to it in your scope.
ChangeNotifier simply implements Listenable and provides some utilities for managing listeners. Furthermore, the documentation states the following about it:
ChangeNotifier is optimized for small numbers (one or two) of listeners. It is O(N) for adding and removing listeners and O(N²) for dispatching notifications (where N is the number of listeners).
I am not sure about options with better runtime complexity for notifying listeners, but you will not run into any issues in a regular Flutter app.
ValueNotifier
ValueNotifier is a pre-made implementation of ChangeNotifier that will notify its listeners when its value property is changed.
This is sufficient for most case, but since it appears that you want to create a custom ChangeNotifier, you can use the source code of ValueNotifier to take a look at an example implementation (it is very straight forward).
If you are just looking to do state management in general, ValueNotifiers usually work great. However, they are not applicable in every scenario. Hence, here is an extensive list with different state management options.
Considering the questions, I think the techniques that fit your needs best and the most popular options are the following:
InheritedWidget as it lets you notify dependents based on what data changed. Additionally, there is InheritedModel as an extension of this and InheritedNotifier that works with Listenable, just like ChangeNotifier does.
The BLOC pattern, which works with streams.
The provider package which is mostly a convenience wrapper for various Flutter state management techniques (InheritedWidget, StatefulWidget, ValueNotifier, etc.).