In bloc 7.2.0, What is the usage of BlocSelector ? I need a practical example for this widget.
BlocSelector<BlocA, BlocAState, SelectedState>(
selector: (state) {
// return selected state based on the provided state.
},
builder: (context, state) {
// return widget here based on the selected state.
},
)
The answer could be found in the documentation:
BlocSelector is a Flutter widget which is analogous to BlocBuilder but
allows developers to filter updates by selecting a new value based on
the current bloc state. Unnecessary builds are prevented if the
selected value does not change. The selected value must be immutable
in order for BlocSelector to accurately determine whether builder
should be called again.
BlocSelector is the optimised version of the default BlocBuilder. When the state changes, BlocBuilder always triggers an update of your UI. However, with BlocSelector you could optimise this and trigger the UI rebuild only when the specific field/property of your state changes. Meaning, despite that the state is different if your selected property remains the same, the UI won't be rebuilt.
Related
I have an entity object, for simplicity lets call it now Todo. I want to have a widget where I can edit multiple of these todos simultaneously, something like EditableTodoList (and this would show a list of EditableTodos).
This widget would recieve a List<Todo> and also something like Function onTodoEdited(Todo).
I am trying to use immutable data, so when an EditableTodo is being edited (and the event gets propagated to the widget which holds the EditableTodoList), I'd create a new List<Todo> which contais the updated Todo, but then EditableTodoList would rebuild with all its EditableTodos inside.
How could I optimize this, that only the relevant EditableTodo is rebuilt? I don't want to hack around with mutating the prop original List<Todo> because that hides greatly an important detail.
Background: currently the state is inside a cubit and I am context.select-ing for every EditableTodo list item the corresponding Todo in the state, this way only the edited item rebuilds. I'd like to decouple this EditableTodoList from the cubit.
Theoretically I assume its not possible, as EditableTodoList is given new properties, so it has to rebuild, and that means all subtree gets rebuilt. EditableTodo cannot be const as its prop is not a constant.
But still, what would be the most elegant way of separating EditableTodoList from the cubit? As it only needs a List<Todo> to show, it should be possible somehow to optimize the rendering of not changed Todos
You should consider how widget, element and render trees work in order to be concerned. There is a great video about Flutter's rendering mechanism. When rebuilding a tree, framework compares the two versions of widgets by using only the key and runtime type values. This means that if you change string value of the Text widget, the same render object with mutated data will be used again. New render object won't be created, which means no unnecessary rebuilds will happen on the render tree. Rebuilding the widget tree is not expensive compared to the render tree.
There is a limit on minimizing the the build scope in the ListView. ListView itself should be rebuilt in order to update an item. So you can't target a spesific item to rebuild. But items can reactively rebuild themselves (eg. an item that listens to a stream can rebuild without effecting the others). Therefore immutable collections doesn't matter in this context since the framework doesn't care the value but key and runtime type. You can either pass a completely modified list or a list with just one element changed, it will have the same effect.
So i am writing a Flutter application that utilize the MVVM architecture. I have a viewModel for every screen(widget) with ValueNotifiers and i want to initiate the viewModel for that view.
Now most guides suggest a Provider approach, but why provide it when i can just normally initiate it.
Code:
class FooModel{
final ValueNotifier<bool> _active = ValueNotifier<bool>(false);
ValueNotifier<bool> get active => _active;
FooModel(){_active = false;}
doSomething(){_active=!_active}
}
What i want to do:
#override
Widget build(BuildContext context) {
_viewModel = FooModel();
return Scaffold(
body:ValueListenableBuilder<bool>(
valueListenable: _viewModel.active,
builder : (context,value,_){
if(value)return(Text("active");
return Text("unactive");
}
)
}
what is suggested:
Widget build(BuildContext context) {
return Provider<FooModel>(
create: (_) => FooModel(),
builder: (context, child) {
final vm = Provider.of<FooModel>(context);
return ValueListenableBuilder<bool>(
valueListenable: vm.active,
builder: (context, value) {
if (value) return Text("active");
return Text("unactive");
});
},
);
}
Now i understand that what i suggested creates the viewModel with every build, but that should only happen when screen is loaded thanks to ValueNotifier so its fine.
I guess i just don't understand the value of providing the viewModel.
Flutter has a different ideology.
yes, you can create Value Notifier and it's fine to do that but just thinking of the bigger picture.
Check this flow you want to call an API then perform parsing and filtering on that and you have 2 views on the screen to show the same data one is to showcase the data and the other one is to interact with data and this update needs to be reflected on showcased data.
to do this what we need to do?
create valuenotifier at class level that encloses both screen widgets.
Call API and filter code at the class level.
pass this valuenotifier to both screen widgets you may ask why right? well because one class need to update other class widgets. and that's only one way to push updates to the valuenotifier is the object itself. so you will need to pass this valuenotifier in both classes.
once you do that and update has been synchronized if any setState has been called to the main widget that encloses both of this widgets then you need to do all this again.
also there will be multiple instances of valuenotifier which is bad as valuenotifier is a stream and you need to close your streams once you're done with the stream so you will be needing logic to close your streams at any setState event on main widget.
What is provider exactly? and how it works? well, the provider is a change notifier class which calls setState when you call notifyDataChanged or notify method. this triggers the widget state change which is listening to that data changes.
and that widget gets rebuild. This is the same logic for each and every state management library out there Bloc, ScopedBloc, or any widget like streamBuilder or ValueListenableBuilder.
In Flutter if you want to change data you just need to call setState. Just to be testable, more readable and maintainable what we will be doing is to separate logic into different files just like we do in Android or iOS and that's where this type of libraries comes into the picture to reduce our headache of typing code all over again and focusing on the main task which is the functionality of the app.
See we can create loops in different formats
for(int i=0;i<length;i++)
while(i++<length)
for(i in 0...length)
It's up to us to provide clean and understandable code so that any other developer does not need to delete all code just because he isn't able to understand our code.
There's nothing right and wrong here in development. It's matter of what is more convenient or what makes more sense. like int i does not make sense but if we replace it with index or listIndex it will.
Also, one thing to mention is what you're doing is creating a model that is kind of the same as bloc pattern. so you're already halfway through. you just need to call state change from model check bloc and other patterns you will understand.
I'm trying to wrap my head around the concept of state, the setState function, and rebuilding stateful widgets. Would this code (inside a method)
setState(() {
newText="some new text";
});
behave any differently from
newText="some new text";
setState(() {});
In other words, does setState(){} only concern itself with what's inside itself, or does it pay attention to state changes anywhere inside its parent widget (or even higher than its parent on the widget tree)?
The setState((){}) rebuilds the current widget state i.e it just calls the build method if you have updated any value inside the setState((){}) or have updated before calling the setState((){}), it will behave same.
For some values which have been initialised or defined inside the build method it will not take any effect, because the setState((){}) just rebuilds the Build() method.
In your case both the setState((){}) calls will behave the same as you have already updated your required value before rebuilding the state. The setState((){}) also updates the values which are dependent on the updated variable from setState((){}) i.e depends upon the variable value which you are updating in setState((){}).
Checkout this interactivity tutorial by flutter for uses
For the setState((){}) method uses checkout this
What I want
I have a simple model. The model extends from ChangeNotifier. If the ChangeNotifier calls notifyListeners() I want to "do" something like showing a SnackBar or Dialog. I provide the model with the Provider package to my widget tree.
What is it comparable to?
I used the flutter_bloc package before. This package offers BlocListener. With BlocListener I can "do" something on state changes. Example code:
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
In the above example, the child will not rebuild but I can still do something depending on the state.
Is there anything comparable to the provider package? I read in the documentation of the package that ListenableProvider would give more freedom to do stuff like "animations". But I do not know if I can use this Provider in some way to show a snack bar on a notify.
Edit: I asked Remi, the author of Provider, on Twitter. With a short amount of characters, he told me that I can use didChangeDependencies for this behavior.
Please be cautious about using didChangeDependencies for this. There are only a few circumstances where didChangeDepdnencies can be used for this, and https://github.com/flutter/flutter/pull/49527 will make it impossible even in those.
The basic problem is that didChangeDepdnencies is sometimes (or, after #49527, always) called at a point where the tree is locked against state changes. Before the pull request, it is only safe on calls that are:
Not the first time (which is called from within a build scope)
Not the time where an element is being deactivated and eventually unmounted, so is no longer in a valid spot in the tree (this call will no longer happen at all after the pull request).
A safer way to do this is:
#override
void didChangeDependencies() {
super.didChangeDependencies();
if (Provider.of(context).whatever == someCondition) {
SchedulerBinding.instance.addPostFrameCallback(() {
// show modal or dialog
});
}
}
This code is safer to use because it is guaranteed to run at a point where state is safe to change in the tree, rather than only working in some very specific scenarios without the frame callback.
There are probably more elegant solutions than this (such as adding a callback directly on notifyListeners for your ChangeNotifier, assuming it only fires when the tree is in a mutable state).
try using listener on your provider
final myNotifier = context.read<MyNotifier>();
void listener() {
// Do something
}
myNotifier.addListener(listener);
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