We know that, we need to put BlocProvider instance on top of widget tree's part, which we want to get access data inside this part of tree. What if we use all BlocProvider instance on top of whole tree, even most of them are only necessary for some small bottom parts of tree. Is it considered as mistake, because of we are passing data across whole tree(despite it is unnecessary) every time we call it, or there will be zero performance differences between putting all blocProvider on top and putting BlocProviders only on appropriate tree parts.
It is considered bad practice to put everything at the top of the tree for several reasons. It breaks several common good programming practices, SOLID amongst others. You e.g. don't have all your variables and class instances in your applications as global variables.
And when it comes to performance, yes it can have a negative effect on performance. If and how much is of course not possible to say before hand because it depends on how many, what the blocs do, how they are used and etc.
Some should obviously be at the top, so they should be. But not all. So provide them only where they are needed as it will be better performance wise and will keep your code cleaner.
Edit:
This is from the creator (Felix Angelov) of flutter bloc:
The main disadvantages of providing all blocs globally are:
The blocs are never closed so they are consuming resources even if they aren't being used by the current widget tree
The blocs can be accessed from anywhere even if the state of the bloc is scoped to just a particular feature
The blocs typically end up needing some sort of "reset" event to revert back to the initial state which is not necessary if they are
properly scoped and automatically disposed by BlocProvider
My recommendation is to create a bloc per feature and provide that
bloc only to the specific subtree that needs it. Hope that helps đź‘Ť
Related
I am writing a relatively simple app in which I need to do some state management. After looking trough all the documentations and many rewrites I need help with understanding how to actually structure and use the tools provided for state management, like the classic providers and riverpods providers.
My questions concern the arrangement of Models which hold state, nesting those objects and redrawing only parts of the widget tree.
My project is a mobile app which lets you keep a shared log of your fuel stops and the money you paid. If you share a vehicle with one or more persons, you all enter a pool in which the fuel entries are displayed. There are models for users, log entries and pools. When a user is logged in, a number of available pools need to be fetched and stored and after selection the members and logs of the selected pool need to be fetched. If updates are made to e.g. the name of the user or a specific log entry, the current view might need to get updated.
Now, the current code is a mess where much of the state gets stored in a pool model, which is provided by a ChangeNotifierProvider at the root of the widget tree. Since I was under the impression that one should try to update as little of the UI as possible I tried to split my state up into different models, which are nested into each other, for example the LogEnries are part of the pool model, but are themselves ChangeNotifier. The idea was to be able to selectively refresh and listen to parts of the state. This has lead to horrible code where I sometimes need to call notifyListeners() from outside my pool model / state object. I want to remedy the situation with a rewrite of my state management.
Now to my question: How would one structure state generally (or my state specifically) for it to be efficient and pleasing to the magical gods that created the libraries? This stackoverflow question from two/one year ago asks a similar question and the provided answers recommend to do one of these things:
Leave the state nested and inject the Models into each other with ChangeNotifierProvider, but apparently that's not great if the provided objects are models
Put everything in one state object whose provider sits at the top of the tree, and maybe use a selector to only refresh the part of the UI which is affected
Nest models but only provide the root an as immutable object and update state by calling functions and copying stuff
I think another approach would be to
use the recently released riverpod package and create a lot of providers for every need.
Now I have no idea which of these approaches is better or valid or if they all work perfectly fine. My questions regarding the corresponding approach would be:
In what order would I nest them? I intuitively nested the Pools in the root state object, the log entries in the pool model but dependency wise I'd probably have to go User->AppState->selectedPool->Logs, resulting in a possible statement of logEntry.selectedPool.appState.user. Feels weird.
This might work but I'd always get the whole state in one model (which is arguably not that big in my use case). One could use the Selector to only refresh parts of the UI, but I think there was a problem with using mutable objects for that because Selector needs to be able to tell if something has changed. Also, as far as I understood I could only use the stuff I've specifically selected and not listen to a different property than the one I'd use afterwards for UI refresh.
Same as the above, also a lot of boilerplate code.
This one seems the most exciting, since riverpod and it's providers look really cool. But would I nest my state or just provide everything globally and maybe inject a few things with ref.watch() in the creating method? Would I create a new provider for every change which I want to listen to separately or is it cheaper to figure that out once I get the object? And since the riverpod equivalent of ChangeNotifier, StateNotifier features only one Value (I think?), would I create a new provider for every important piece of information I need?
As you might have noticed, I tried to look up a lot of stuff but haven't quite figured out how to translate all the techniques to an actual project beyond code demonstration size. I would be immensely thankful if someone could explain to me the correct approach to structuring state management in general, which approach might be the best one for my specific situation and most importantly what might be the reason to decide against other ones. Please don't hesitate to point out any mistakes I made, although stackoverflow has a reputation suggesting this might not be an issue. If anybody wants to have a look at my code, there's a branch where I started to work towards a better modularization starting with an AppState Model and reworking some functions.
I'm slightly new to Flutter and just want to ask some questions/clarifications regarding the development using it. I am currently building a flutter app and wanted to change the layout based on different devices and orientations. I created 2 different dart files containing different app layouts of my Login page (LoginMobile.dart and LoginTablet.dart respectively). I created also a separate dart file (LoginComponents.dart) to store "all" the object UI/components of my login form (txtEmail, txtPassword, btnLogin, etc.). I heard doing like Widget txtEmail() {return TextformField(...);} is not advisable as it can affect the app performance, so I tried making them as classes. Am I doing it right? Is it okay to store multiple stateful widgets in one dart file(?) since the txtPassword have a setState() for show/reveal password and the btnLogin for the authentication process. Is there any negative effects that I may face in the long run if I continue doing it this way? Any tips and advise were highly appreciated. Thanks!
Storing your widgets in a single file is okay but would cause confusion when making a large app. when the amount of widgets is getting increased in that file it would be harder to do a small change because its harder to find the widget.
i would recommend using multiple files, so you can find them and organize them easily.
Yes, you can. But point comes to maintainability. I prefer to keep one public widget which having the same name as the filename and remaining private widgets.
So now ques is How many widgets in a single file?
Its actually depend there is no such rule to restrict the limit of file. Different authors having different preference. I prefer try to keep 5-6 classes(widgets) and
each one having 5-6 functions.
Try to make a file single responsible i.e(5-6 classes together responsible for single functionality). Don't make god class which having unrelated concerns together later it will pains(haha)
If it's a common widget keep them separate to respect DRY principle(Don't repeat yourself)
If the widget is further divided into 3-4 widgets or it children widget change depend upon rest response keep seprate for good practise
Bonus Tip: try using code folding shortcuts to push a little more
New to Flutter, so please forgive the question.
I'm playing around with the need to manage state (variables/objects) across the entire app using the Stateful widget - it's a bit cumbersome, but I get the method.
I see there are packages providing similar functionality (scoped_model and provide) - what do these bring to the mix and what problem do they solve? Before embarking on one particular approach, I guess I'm asking what the seasoned Flutter devs are using and why?
Thanks
It's mainly about scalability & performance of your application. Using StatefulWidget is fine for small apps, but imagine if you had a widget tree of a depth of 30, and only 2 leaf widgets need to know about some counter value, and they're both at opposite ends of the widget tree. With StatefulWidget approach, you'd have to place the value at the top of the tree and pass it down the entire tree so the 2 widgets can get it. Then, after a while, you need another widget in a totally unrelated branch of the tree to get counter as well - now you need to modify that entire branch to also pass down the value. Then, later on, you decide to move one of the original leaves to a different place - again, you have to modify your entire codebase to accommodate that.
Using InheritedWidget makes that both provider and scoped_model use, you can instead just inject counter at the top of the tree and have the widgets that require it simply extract the value from their context using a Consumer or the scoped_model equivalent. This will also solve another issue: now that none of the intermediate widgets know about counter, they no longer need to rebuild when the value changes. You can now move your widgets around and add/remove dependencies on counter as you please and not mess with unrelated widgets as you do that.
You can even go a step further and use blocs instead. I recall reading an article that compared all approaches and found that blocs can further improve performance of your app by eliminating some builds, though it can be a little daunting to understand what's going on in the bloc pattern at first.
Using StatefulWidget only is not bad.
You don't have to use provider/scoped_model.
StatefulWidgets are very powerful and scalable by default.
Their shortcomings are:
they are very verbose
it is difficult to reuse stateful logic between stateful widgets (although there are variants for it, like flutter_hooks)
refactoring can be painful
These are things that InheritedWidgets solve, so provider/scoped_model too.
But as you can see, these are mostly quality of life issues.
If you can support them, it's fine to use StatefulWidget only.
Am I wrong or if we just want to pass a value down the Widget tree, Provider is just an InheritedWidget with a dispose method?
Yes. Provider is indeed mostly features based on Inheritedwidgets.
If you want to make your own, then that's fine. But you'll quickly realize that, without provider, you'll have hundreds of useless repetitive lines.
Provider basically takes the logic of InheritedWidgets, but reduce the boilerplate to the strict minimum.
Provider is not a must, but should.
First of all, it's promoted by Flutter Team and flexible enough to handle almost any state-management solution.
It might not be fair to say that InheritedWidget with dispose because Provider has too many different use cases and inherits some optimizations probably you won't find anywhere else.
If you use InheritedWidget in large application, build methods always rebuilds whole build method. But with Provider you have Consumer widget which is can be very specific to control specific blocks of build method, so you have more efficiency. Also listeners have less complexity than InheritedWidgets'(O(N) vs O(N²)).
The problem is since Flutter was intended to be a UI framework at first, the default state management solutions are also UI oriented.
Lastly, since you'll need different state-management patterns for different projects, one package-for-all scenario is invaluable imo.
The Flutter docs have a good section about this where they're talking about state management in your app (a big part of which is passing values down the tree).
Flutter has mechanisms for widgets to provide data and services to their descendants (in other words, not just their children, but any widgets below them). As you would expect from Flutter, where Everything is a Widget™, these mechanisms are just special kinds of widgets—InheritedWidget, InheritedNotifier, InheritedModel, and more. We won’t be covering those here, because they are a bit low-level for what we’re trying to do.
Instead, we are going to use a package that works with the low-level widgets but is simple to use. It’s called provider.
So as of late 2021, it seems the recommendation is to use the provider package unless you need lower level access- in which case you could use the Inherited* widgets. For example, if you wrote your own version of provider then you'd need that lower level access.
The doc I quoted above is at https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple#accessing-the-state
I need manage the states globally, I find a lot of way, in terms of managing the state by using Provider bloc pattern redux and etc.
But actually I dont know, which one is faster and performant?
Example: I am working on chat application, which I have to manage socket connection messages online offline status all as globally. the states need to be accessible from all screen, like ChatList screen, ChatBox screen and more...
I didn't test them all performance wise. And i do not think it will make much of a difference.
Provider works with inheritedwidget as scoped model i think.
I love the streams for the versatility of the data flow.... i think the key part for performance is to keep the rebuilding/painting of the widgets that require it at the lowest level of the tree.
get_it package should help you to keep those streams accessible everywhere, is a great simple package to keep neat model access, regarding the state management solution.
For instance, i believe that generating statelessstateful widgets instead of functions that returns widgets to make the layout, provides more performance, for the separation of buildcontexts.
In any case, the framework is super optimized and performant... if u run into any issue, u can easily track it down with the devtools and the community is very supportive.
Btw, take my basic reply with a grain of salt, as I've been only playing with flutter/dart for a week.