how can i access to data from another bloc - flutter

hey guys i'm new with bloc pattern and i have some questions
How I can get props data from a State inside BlocBuilder for another bloc ?
already worked with provider (state management) and it's easy to access to any data from everywhere , is that possible with bloc and how ?
thank you

Hoping that I understood your question correctly,
You have a piece of data stored in state in bloc A and you want to use that data in bloc B.
For instance a post Bloc which needs to fetch all the posts by a logged in user (assuming that the logged in user has been stored in state in the user Bloc).
Defining the event:
class FetchPost extends PostEvent{
final User currentUser
}
when dispatching the FetchPost event:
Note: if you are dispatching the event from your view, you have to get the bloc from Provider.of(context)
PostBloc _postBloc = Provider.of<TransactionBloc>(context);
UserBloc _userBloc = Provider.of<UserBloc>(context);
_postBloc.dispatch(FetchPost(_userBloc.currentState.loggedInUser))

To access other blocs props you have to hold its instance, and from it, you can acquire its state. I have addressed this in the blog post that I have written.

thanks guy i think i find the solution of this question
ist's data shouldn't be in the bloc, data should be in a repository. Then, you can use RepositoryProvider or MultiRepositoryProvider in order to get any data from any bloc in the subtree.

Related

Flutter GetX Auth ever function

I am completely new to GetX and want to learn an easier state management system than bloc ( I started with BLoC). So the first thing I wanted to learn is how authentication works. I found this tutorial online: https://dev.to/imransefat/firebase-authentication-with-getx-in-flutter-4ik8 and asked me a question.
Inside the controller, the author bound two streams. One for the user and one for the googleSignInUser and he also added an ever function for googleSignIn:
googleSignInAccount.bindStream(googleSign.onCurrentUserChanged);
ever(googleSignInAccount, _setInitialScreenGoogle);
. When I user exactly this source-code and add a Firestore crud controller with a Todo-list, I get a null value on the variable auth.currentUser! on the Stream for the Todo list ( firebaseFirestore.collection('/users/${**auth.currentUser!**.uid}/FoodList').snapshots().map((QuerySnapshot query) {... )
When I remove this function inside the onReady method, everything works fine. If I understand this correctly, I don't have to listen to the googleSignIn stream specifically, it should be enough to listen to the user stream. Is this a mistake from him, or do I misunderstand here something? You can find the complete source code on the website.
Second question is: Before GetX I always check if a user is authenticated or not with a StreamBuilder inside the Material app:
StreamBuilder<User?>(
stream: auth.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return const RootPage();
} else {
return TutorialRoot();
}
With GetX I saw this appoach with the _setInitialScreen(User? user) method and the
ever(firebaseUser, _setInitialScreen);
call inside the onReady(); - Is the StreamBuilder a bad practice when using GetX, or still a legit way of checking the current auth status? In my opinion the user expirince is a little bit faster with the StreamBuilder that why I ask for this.

Flutter reset all provider states after sign out

Whenever I sign out of my app, it seems to not clear all provider states and when I log in to another user my app crashes. Is there way to reset everything to default when performing logout action?
It depends on the scope of your provided objects. If you provide them at top level, the instances will not be disposed and live on.
Possible solutions could be:
Provide your state further down in the widget tree.
Observe a logout event in your state and perform reset of state automatically. There are multiple ways to do this, e.g. use a ProxyProvider.
ProxyProvider<Session, SomeStateClass>(
create: (_) => SomeStateClass(),
update: (_, session, instanceOfStateClass) {
return instanceOfStateClass..reinitialize(session);
}),
In the example above, the update method gets called, when Session notifies about changes.

Best way to use BLoC as global state management

So I have a BLoC which I need to access globally through my app - CurrentUserBloc and its purpose is to hold data of currently logged in user. It can hold some states like CurrentUserWaiting, CurrentUserReady, CurrentUserError etc. Some of them hold user instance - like CurrentUserReady, and some don't - like CurrentUserWaiting. Now I need to access this user data in order to send an event to another BLoC. For example I want to post a photo and I need userId of currently logged in user to do this. But I can't just use BlocProvider.of<CurrentUserCubit>(context).state.user to get user data because some of this bloc's states - like CurrentUserWaiting - don't store user property and compiler won't take this.
I get around it by creating abstract state class CurrentUserWithUserInstance and extending it in states that hold user property. Then I just access state like this:
final currentState = BlocProvider.of<CurrentUserCubit>(context).state
as CurrentUserWithUserInstance;
Then I get user property from this and use it to add event in another BLoC.
I was wondering what would be a better way to do this. I need to access user data in multiple places in the app and I don't know if this is a good approach. I know I could use just one state class with all properties and then change it by copyWith method. By that doesn't really seem that good to me.
How do you store and access global state using BLoC?

Flutter: BloC inject mocks in app testing

I'm trying to create a flutter app using flutter_bloc, firebase auth and firestore.
I following flutter_firebase_login example which is truly amazing for all the testing coverage.
I would like to go one step further. Once the use is authenticated, I want to load the user profile from firestore, then actually display the app. (In practice, once the profile is loaded, I will have to do new firestore lookups that will depend on the profile info).
So I kind of have a chain of events:
Authenticate -> Load profile for user "uid" -> Load data depending on profile.
I'm wondering what is the good way to do that which still allows me to test my full app using mocks only.
The example injects the authenticationRepository into the App class then we can inject it in the test. My problem now is that, once the user is logged in and we redirect to the HomePage widget, this widget will have to create a new provider. But if it does create a new one, then I can't inject it anymore.
What is the good practice there? Here are the few options I've been considering:
Inject all the providers in the main()
I guess this would be the simplest solution. Though since those providers are kind of chained, I would have to pass the context data to every call on the "sub" providers, the context from the previous one. For instance:
ProfileRepository {
... getProfile(uid);
}
DataRepository {
... getData(... profile)
}
Dynamically build the providers
Ideally, I would like to not need those extra params in my providers and instead build my providers with those context values. Example:
ProfileRepository {
ProfileRepository(uid)...
... getProfile();
}
DataRepository {
DataRepository(profile)...
... getData()
}
So each time the uid changes, we would create a new provider for the profile and for each profile change we would create a new data provider.
This will simplify the calls in my app to not have to load the profile to get the data. The sub widgets just need to get the current provider and call the functions without the depending contexts.
Though just calling the constructor from my widgets would create problems for the tests DI which means I would have to create provider factories that I could then inject. And from the tests I would pass mock factories and in my main(), the prod factories.
Adding a state to my providers
I would inject all my factories in the main but instead of constructing them using the uid or the profile. Pseudo code:
ProfileRepository {
setUid(uid)...
... getProfile();
}
DataRepository {
setProfile(profile)...
... getData(... otherParams)
}
Each time the user changes or the profile changes, I just call the setters. That way I don't need to pass provider factories from the main.
Note
I considered to wrap the AuthenticationRepository into a UserProfileRepository which would remove one step here but for the data, this would not work.
I'm not sure what is the good practice here and would love to get feedback.
Thank you in advance!

Flutter cookbook for widget that gets its state from a REST API and refreshes automatically?

What is the basic cookbook for a flutter widget that does this?
1) Displays initial state like "loading".
2) Async gets content from a REST API.
3) Updates state when the REST API returns success.
4) Refreshes content on a timer.
You may want to take a look here.
Generally speaking, you will have a StatefulWidget that calls the API on it's initState and store the "future" (async action in Dart) locally.
Then use FutureBuilder to know weither or not the data is loading/fetched/error. And display something accordingly.