I use the provider package to manage my application state. I have a few questions concerning how to manage the state in the application.
Is it a good practice to create a ChangeNotifier class for each screen in my application to handle the back end for this page (which is provided to only this screen) ?
In an example like this:
If i have a page that have multiple widgets and i need to rebuild a small part of the page like adding a new TextField on enabling a switch.
in the previous example
Should i use a provider to only rebuild the small part of the page or this part is mostly handled by only using changeState() ?
in case that the local-state of the page should be handled in the screen.
Where should i place the logic of the page, like http requests on button clicks and loading data for this page ?
If the state that you are updating is only needed within one widget with one or two down widgets down the tree, I would recommend using the built-in SetState. While both Provider and SetState would work for any form of state management, I tend to think of Provider as similar to React Context.
Provider is great for holding state at page levels or if you want to maintain the separation between widget builds and logic in different files.
SetState is great for local widgets with not a lot of nested widgets underneath.
Here is a great article that discusses the different state management solution approaches. At the end of the day, it's up to preference!
Related
I've been coding with dart and flutter for over a month now, one thing that I was recommended to do by my friend is to learn Bloc as it would be helpful for big projects for businesses. From watching Videos on Youtube, reading documentations on it and also looking at Github repo's I've still not understood why we need to use Bloc and its features (FYI: I've only started using Bloc the last 2 days') Would appreciate if someone would explain what's the purpose of using Bloc as opposed to just normally coding.
Benefits of using Bloc pattern
It follows SOLID principle.
Your business logic is decoupled from the UI.
You can use same Bloc object in various screens. For example if you are developing e-commerce app, you might want to show cart icon with items added on many screens and items could be added to cart from any screen, you don't have to pass around Cart object or Function to addToCart.
You instantly get notified when Bloc state is changed and you can build your widget based on new state. This also handles unnecessary builds.
You can change any implementation of business logic (like form validation) in the bloc and your UI will not need any change.
Adding Analytics to the app is also convenient.
Less logic in Widget classes means easier readability.
You can transform events passed to Bloc. (in case if you are showing search bar and on every letter type, you are making a network call to show search suggestion, you can add debounce to certain time).
You don't have to check for Authentication in every screen.
You can respond independently to various state changes of Bloc for showing Snackbar/Toast in any screen.
Less number of items passed while creating widget class (as many properties can be accessed from Bloc object)
Follows MVVM pattern which says model, viewmodel and view should be independent of each other so that future modifications/ scaling/ debugging is easier.
There could be many more benefits which others can tell. You will only realize them once you would have started using the Bloc after working with a project which does not have state management.
Sidenote: flutter_bloc library is an option to implement Bloc pattern. Bloc pattern was showcased by Google and you can write your own implementation as well. But the flutter_bloc library is very robust.
BLoC or any state management protocol will only help you to separate data and presentation layer in your project. It will prove useful when a company has to grow its tech team or if they are planning to separate front-end and back-end development.
I'm relatively new to Flutter and Cubit pattern and I'm trying to figure out which are the best ways to work with them. Recently my colleague and I have been struggling to reach an agreement where we should inject the cubit and the repositories.
Reading the bloc/cubit documentation, it is not very clear about where we should do it.
IMO, everything that we need to instantiate, should be injected as high in the tree as possible where two different components that will use this information have in common.
For my colleague, each widget can instantiate one cubit, meaning that each widget will have its own instance of the cubit.
I would like to discuss about what are the community thoughts and best practices regarding the dependency injection and architecture regarding cubit.
There is no single answer to that question. It all depends on your project structure and architecture. In general though:
It's OK to create a few cubits/blocs in one screen/widget. Some widgets or screens contain more than one business logic stuff. Cubits are just classes that help you maintain the state, but it's no different than having many animation controllers or text editing controllers, it's just that it serves a more high-level state management. Let's say that you have a comments section in your app. You may have:
a cubit for the comments themselves, to load them, load more on scroll, report error when loading failed etc.
a cubit for each comment that manages the "Like" button under a comment
It's perfectly valid to have it that way.
It's OK to have global cubits for the whole app. There are some things that you need to have access to from the whole application. It usually is navigation (Navigator), and some theme management (Theme), why not something more business-logic related then, like authentication logic, current user context, user's app preferences, etc.? :)
IMO, everything that we need to instantiate, should be injected as high in the tree as possible where two different components that will use this information have in common.
This is a good approach. Most frequently it will be above your routes, so somewhere above your MaterialApp. If you make use of nested Navigators, then this common place could be above this nested Navigator.
On a more technical side, how will you manage the dependencies used in those cubits/blocs is up to you and your liking. I find some of the options:
Instantiating all repositories and other dependencies in main.dart method and then passing them in constructors to your blocs/cubits in Providers.
To reload those dependencies you will need a Hot Restart though, Hot Reload won't be enough.
Putting your dependencies in the widget's tree with Provider, just like blocs/cubits.
Using riverpod instead of provider.
Using a Service Locator pattern with get_it and injectable combo.
The most correct choice will be something that you (and your colleagues) are most comfortable developing with and that scales well.
I have an application which required the writing of many blocs.
Several pages use the same bloc. For example, messaging pages use the MessagingBloc.
Currently, I use a global multi-provider to dispatch blocs to child widgets. The problem is: when I change pages (so I no longer use the messaging feature), the bloc is, logically, still present in the tree structure.
Do you know a way to have in the tree, only the blocs that are currently in use? (maybe working with one Navigator by feature but it seems too complicated/expensive)
I'm getting ready to write my first nontrivial app with Flutter and Provider. I've read up on how Provider facilitates immutable widgets (StatelessWidgets). My question is, is it always an antipattern to use StatefulWidgets when using Provider? If not, what are examples of when it better to use StatefulWidgets in a Provider app?
EDIT
It's been a couple months using Provider and I'm still favoring it over StatefulWidgets in every case. Every now and again I introduce a StatefulWidget, mostly to try to gain familiarity with them, and almost immediately regret it and refactor to Provider. The other day I ran into widgets not refreshing because they were identical types, so was looking at introducing keys so they would refresh. First couple attempts failed, so I refactored into Provider and everything just worked (without the need for keys).
Antipattern was not the proper term in my OP. I guess my question is, are there examples where StatefulWidgets are cleaner or otherwise easier/better to use?
provider doesn't care whether you write stateless/stateful or anything else (hooks?).
It removes the need to write a StatefulWidget in many situations, but it doesn't claim that you should use StatelessWidget only.
In the end, it's your job to decide if you need a StatefulWidget or not. You may need it when writing animations for example.
Adding to RĂ©mi's answer and new to this implementation:
use Provider for shared models
use widget state to manage the model that is specific to that concern when it's needed
imagine a user object after auth, null before, shared through an app, with a form with state specific to editing fields, like a nickname, or whatever, updating local state and possibly propagating out to the rest of the product (when finished updating on the backend?...who knows) and that state is disposed of when that view isn't needed anymore, but the user reference remains via the provider reference. It doesn't make sense to manage all that state change in the provider model--that's where the result goes.
Making a few assumptions here based on my experience with React+Redux as well as passing objects around a native Web Components (similar lifecycle to both of these) as well as LitElement. The patterns seem similar if not the same so-far.
Provider.of<ProviderClass>(context, listen: false);
The Provider is one of state management mechanism which Flutter has, under the hood, Provider keeps track of the changes which are done inside the widget. It doesn't matter to Provider whether it's a Stateless widget or Stateful widget, It's gonna rebuild widget if anything gets change.
listen: false tells the Provider not to rebuild widget even if data gets modified. That means it can only re-build if the parent widget gets modified by setState() or by the ProviderClass class value gets modified.
I'm working on a prototype for a storefront, and I have a slider where I have the option to see the user's profile. Every user has to register first before they can access the store (is just a prototype).
When a new user registers successfully, they will be immediately sent to the product catalog screen. On the same catalog there will be a slider, and in that slider there will be an option to see the user's profile page.
My question is, how can I send the user's info (name, email and phone number) through the catalog page, then trough the slider, and then to the user's profile page?
I already have a class that holds the user's info that's created on the RegisterPage class/screen.
Unless I'm reading the question wrong, it sounds like some kind of state management solution would be useful here. That is, once you know the user's details, they should be stored in a place that is easily accessible later on from other widgets.
There are a few state management options available:
StatefulWidget - a classic, simplest approach. Have a StatefulWidget which tracks state (user's details), and pass them down the widget tree to a component that can make use of those details. Gets a little unwieldy if you have a deep tree and need to pass the data down through several layers that don't really care about said data.
InheritedWidget. Propagate information down the widget tree and rebuild UI whenever inherited widget itself changes state. Relatively straightforward, simple solution. Unlike StatefulWidget, you can retrieve required data where you need it, and you don't have to pass it down as arguments to yet another widget.
Provider package. A state management solution by Remi Rousselet, endorsed by Google itself. Easy to use and understand, and quite scaleable. Advertised as:
A mixture between dependency injection (DI) and state management, built with widgets for widgets.
Redux. Another state management solution that comes in a form of a package. If you've worked with React/Redux, you will feel right at home. It's not as full-featured as its JavaScript counterpart, but the idea is the same: have a store to which some widgets are listening, and rebuild them whenever data changes.
BLoC / Rx. One of the Google's recommended ways to manage state. Leans heavily on streams. Is somewhat more complex to understand, but rather powerful once you do.
MobX. Another state management solution ported from JavaScript world. I haven't had much experience with it, but I believe it's based on observables, actions and reactions. I expect it should be quite similar to JavaScript's counterpart.
You can read more about each of those by heading over to the dedicated page on the official documentation.
Personally, I'd probably choose something relatively simple first - perhaps InheritedWidget or provider package. However, it heavily depends on your use case and what programming paradigms you're comfortable with / want to experiment with.