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.
Related
What are the actual advantage(s) of Bloc over Cubit?
In addition to traceability (which you can also achieve with appropriate logging in Cubit), and advanced event transformations (I can't think of any "advanced" event transformations that Cubit can't do, since there is always a way to do it with Cubit. And if you're using clean architecture, domain/data layer can help with complex data manipulations).
Sharing and sourcing events
These are the things that I'm looking for that should be able to do with Bloc since these things can't be actually done with Cubit. However, it appears that these are impossible (or is it?) because adding event on a Bloc requires you to identify the actual Bloc where the event will be added. bloc.add(YourEvent()).
Also, event sharing is somewhat debatable because this can lead to a bad architecture/hard to maintain.
For event sourcing, I can't find in the docs if this is possible (reversing back to a specific past state?).
Am I missing something here?
As far as I know reversing to past state can be easily done when you have immutable states regardless of whether it is bloc or cubit. Having immutable states allows you to store list of states and restore whenever you need a specific state.
Bloc has no advantages over cubit but rather different purpose. In cubit you have action=>response (function=>states) whereas in bloc you have streams.
What cubit cannot do?
For example you can have two events being processed concurrently when using bloc (since bloc 7.20) but you cannot call two functions simultaneously on cubit.
Sharing events
You can share events implementation between different blocs because you have to specify what events bloc implements.
class MyBlocA extends Bloc<MyEvents, StatesA>
class MyBlocB extends Bloc<MyEvents, StatesB>
If I understood correctly, what you want to do is to process a single event in two different blocs, which you cannot do because event is emitted to a specific bloc. So it requires two calls:
blocA.add(EventA);
blocB.add(EventA);
Depending on your case you might listen to state of MyBlocA inside MyBlocB. This way whenever event for MyblocB appears, the action would depend on the state of MyBlocA.
Blocs and Cubits are same in terms of state management with only one difference of state mutation: Bloc is event driven and Cubit is method driven.
Apart from all of this, in terms of architecture not much is different as of now. All others have been mentioned precisely by #chris in the above. It is up to the developer on how to maintain the state in a way is manageable for us.
aren't events for dependency injection?
Cubit
call Action
set State
Bloc
trigger Event (inject something, depending on screen/page it was trigger from. as Example)
then call Action
and set State
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.
I have an application where I display a list of cards that represent a model (Let's say a Person). These are stateless widgets as they cannot be changed directly. These instances are obtained from an API and, since the amount of items is large, I am using AutomaticKeepAliveClientMixin to keep them from reloading and triggering more API calls.
When clicked, these cards lead to the Person's page where there we can edit some information on them. Using a StatefullWidget here with setState takes care of all issues related to the page. However, when I pop the individual page the card that was clicked does not reflect the changes made.
I was thinking of writing a ChangeNotifier wrapper for each Person but from what I've read this is a bad idea. Using more powerful state management tools like BLoC or Redux seems like overkill too. How can I implement this properly?
I think you should try:
ontap: () async {
await Navigator.push ....);
ref
}
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.
The scenario is this. I want to show the user one or two items, but I don't want to keep showing the same items over and over again. I don't think Firebase functions will retain state because each function call will activate the function again. So how do I maintain state without having to store it in the database.
No, Firebase Functions don't retain state. In fact, you're not even guaranteed to be running on the same server in between calls to the same webhook.
If you want to maintain the state during the conversation, but between different parts of the conversation, you have two good ways to do it:
If you're using the actions-on-google JavaScript library, you can put data into the app.data field and it will be available in the same place in the next call. (I can't find documentation on this, but its reported in https://plus.google.com/105458329026934344336/posts/Xr1KPiMPzpH)
Since you're using Dialogflow, you can add the state as parameters to a Context. These parameters will remain in the Context, and available to future Intents that expect it as an incoming Context, as long as the Context is active.
If you need to maintain state between conversations, you will need to save that state, probably associated with the anonymous UserID that is passed to you with each request.
These methods are similar to what you have when you're working with web requests for a user.