I have a screen (a stateless widget) in which I have two buttons, one to check if Firebase account is verified and the second for resending verification email. These two processes are obviously separate and I need to separate them in two cubits.
So, my question is how can I do it?
I guess I can do that with MultiBlocProvider, but I am not sure how can I get states from those two cubits in this scenario? Is there a best practice defined for this type of scenario?
First, it is no problem to run a MultiBlocProvider to the screen and then have two BlocBuilders in parallel, e.g. one for each button or nest two BlocBuilders (which is essentially what .watch() would be if it is in another BlocBuilder).
But I have an opinionated answer as well. The two buttons will as you say run two separate processes, but I wouldn't separate them into two cubits as they are so tightly linked to the same feature and essentially the same state of that feature. I think a clean solution will be one cubit with separate methods, a HandleFirebaseVerificationCubit with a resendEmail()-method and a checkVerification()-method. Because I guess you'd want to either hide or disable buttons depending on a common state (e.g. NotVerified/Verified) etc.
I'd compare this to a form where you have a backend handling e.g. some validation which is triggered by a buttonpress and another button fetching some data to assist with populating textfields (e.g some address) You'd probably have one cubit for the entire form.
Related
What's the best approach to make something like parent-children bloc architecture? Very often I face a problem when there is a need to establish communication between cubits or blocs.
Let's image a form where we would like to create a new user:
User name
User role (separate cubit, fetch all possible option from API)
Calendar (separate cubit, a lot of calculations made)
Apply button (main BLoC which is responsible to save new user). First
approach:
We need to get each cubit's state and emit new state when clicking on Apply button.
First approach:
var role = context.read<RolesCubit>().state as RoleSelected;
var date = context.read<CalendarCubit>().state as DateSelected;
context.read<CreateUserBloc>.add(CreateNewUserEvent((role: role, date: date));
Pros:
good granulation,
each small cubit is responsible for one thing eg getting a list of available roles and choose one
easier to maintain tests,
cubits can be reused in many places
Cons:
a need to remember to update in each place where main CreateNewUserEvent is added (imagine we would like to add 3rd sub cubit responsible for Access or Salary).
need to know each sub-cubit's state before we add "main" event. I should copy this logic to other places where this event is added. Maybe another example: I wanted to follow this approach with paginated list, on scroll refresh indicator action and one of sub page, therefore I had to check each sub-cubit state and after that I could add main event CreateNewUserEvent;
Second approach:
context.read<CreateUserBloc>.add(DateChanged((newDate));
context.read<CreateUserBloc>.add(RoleChanged((newRole));
context.read<CreateUserBloc>.add(CreateNewUserEvent(());
Create one big BLoC which can do all responsibilities.
Pros:
everything is kept in one place. When we select new role or new date,
"master" BLoC is immediately informed about change and decides what
to do next.
Cons:
big piece of code which is hard do maintain and test smaller parts
can not be reused in other places because it's monolith
Third approach
Stream subscription and make "master" bloc strictly dependent of sub-cubits. Master's cubit constructor requires a stream of sub-cubits. Explained here:
I hope I explained a problem in a simple way. Whats the best approach to maintain complex architectural design in flutter?
I was wondering , since I started using RiverPod , if I should not use setState at all and have almost everything in StateNotifierProvider
Yes you can. You need to understand there are 2 types of state:
Ephemeral(Local): This is contained to only a single widget and not used for passing information between different components. You should use setState and internal state variables for cases like these. Like #Ruchit said in his comment above, a good example is a checkbox, switch, dropdown. Or if you want to hide/show something based on some data.
Global: This is for any information that is passed between layers, components or widgets and should be accessible and synced across different screens. For these cases you should use state management solutions like Provider, Riverpod etc. Some examples are:
Adding items to a cart.
Updating a favourites list.
Sending data to network layer to make http calls etc.
USE CASE 1:
Lets say I have a screen which displays 3 different lists, List-1, List-2, List-3 (display as horizontally scrollable lists).
The 3 lists are fetched from 3 different network requests. And I am using BLOC pattern to contain all network request inside and BLOC and then feed the result back to page using streams.
Now, which is better way to do this:
Use Single StreamBuilder wrapping the whole state of page (all the 3 lists) and in Bloc load all 3 network request and send the updated State through stream.
Use 3 StreamBuilders for 3 lists listening to 3 Streams in the BLOC. So as each network request completes only the corresponsing list Stream is triggered and built.
USE CASE 2:
A Login page with Components:
User name and password textFields, where user name shows list of suggestions using Stack
A submit button with support for CircularProgressIndicator within it.
Using 1 StreamBuilder to wrap whole state or Use 2 StreamBuilders for 1 wrapping textFields and 1 StreamBuilder wrapping submit button. So only Button will be rebuilt if Loading state changes.
Are there any tradeoffs or performance issues caused by having Multiple StreamBuilders in a single screen?
UPDATE: Added another use case.
I would use different streams. First of all, looking into the "official" bloc examples, you will find multiple blocs for a page, for example filtering vs list.
In your example, if you have 3 network requests, you may get 3 different answers at different times/speeds. So for UX, I would show what you get and not wait, until the last bit got transmitted
I'm working with the flutter_bloc library. Imagine the situation, that you are navigating deep in your app and every screen on the navigationstack presents data (slightly differnet because otherwise it wouldn't make sense), that can be modified by the user. Because we are using Bloc, every screen is connected to it's own bloc. Now, the user modifies the data.
My question: How can I tell the other Blocs/screens to rebuild with the updated data?
To my understanding, the blocs on the routes which I'm not currently viewing, get closed. So they don't listen to events anymore.
EDIT: This assumption is wrong, see answer.
Final answer. My assumption was wrong. Blocs don't get closed, if the route is still on the navigation stack. So you can still add events to Blocs, which are on other routes.
Me and my team are currently rookie developers in Objective-C (less than 3 months in) working on the development of a simple tab based app with network capabilities that contains a navigator controller with a table view and a corresponding detailed view in each tab. The target is iOS 4 sdk.
On the networking side, we have a single class that functions as a Singleton that processes the NSURLConnection for each one of the views in order to retrieve the data we need for each of the table views.
The functionality works fine and we can retrieve the data correctly but only if the user doesn't change views until the petition is over or the button of the same petition (example: Login button) is pressed on again. Otherwise, different mistakes can happen. For example, an error message that should only be displayed on the root view of one of the navigation controllers appears on the detailed view and vice versa.
We suspect that the issue is that we are currently handling only a single delegate on the Singleton for the "active view" and that we should change it to support a behavior based on the native Mail app in which you can change views while the data that was asked for in each one of the views keeps loading and updating correctly separately.
We have looked over stackoverflow and other websites and we haven't found a proper methodology to follow. We were considering using an NSOperationQueue and wrapping the NSURLConnections on an NSOperation, but we are not sure if that's the proper approach.
Does anyone have any suggestions on the proper way to handle multiple asynchronous NSURLConnections to update multiple views, both parent and child, almost simultaneously at the whim of the user's interaction? Ideally, we don't want to block the UI or disable the buttons as we have been recommended.
Thank you for your time!
Edit - forgot to add, one of the project restrictions set by our client is that we can only use the native iOS sdk network framework and not the ASIHTTPRequest framework or similar. At the same time, we also forgot to add that we are not uploading any information, we are only retrieving it from the WS.
One suggestion is to use NSOperations and a NSOperationsQueue. The nice thing about this arrangement is you can quickly cancel any in-process or queued work (if say the user hits the back button.
There is a project on github, NSOperation-WebFetches-MadeEasy that makes this about as painless as it can be. You incorporate one class in your classes - OperationsRunner - which comes with a "how-to-use-me" in OperationsRunner.h, and two skeleton NSOperations classes, one the subclass of another, with the subclass showing how to fetch an image.
I'm sure others will post of other solutions - its almost a problem getting started as there are a huge number of libraries and projects doing this. That said, OperationsRunner is a bit over 100 lines of code, and the operations about the same, so this is really easy to read, understand, use, and modify.
You say that your singleton has a delegate. Delegation is inappropriate when multiple objects are interested in the result. If you wish to continue using a singleton for fetching data, you must switch your pattern to be based on notifications. Your singleton will have responsibility for determining which connection corresponds to which task, and choosing an appropriate notification to be posted.
If you still need help with this, let me know, I'll try to post some sample code.