Hello,
I have a question regarding the best approach for working with streams in BLoC. Below is one specific use case, but I was wondering about similar approaches in other use cases.
What I am trying to do:
SelectAddress
.State
. I am receiving Address
object (latitude, longitude and etc.) with an SelectAddress
event, pass it to GeoFlutterFire library method and get Stream<List<Store>>
.State
with new values from List<Store>
.State
changes, I change view (showing user locations nearby). Where I am stuck
First part works, second and third does not. Last part is OK.
I have a repository, which returns Stream<List<Store>>
from Firestore (plugin is https://pub.dartlang.org/packages/geoflutterfire), but this stream emits at least 8-9 events, before it returns list with documents.
I am trying to listen to this stream in mapEventToState, but StreamSubscription does not work at all:
if (event is SelectAddress) {
yield state.copyWith(isLoading: true);
try {
StreamSubscription streamSubscription;
Stream<List<Store>> _storeListStream =
_databaseInterface.getNearbyStores(event.deliveryAddress, 5);
streamSubscription = _storeListStream.listen((stores) async* {
if (stores.isNotEmpty) {
yield state.copyWith(
isLoading: false,
deliveryAddress: event.deliveryAddress,
isAddressSelected: true,
listOfStores: stores,
);
} else {
yield state.copyWith(isLoading: false);
}
});
} catch (error) {
yield state.copyWith(isLoading: false, error: error);
}
}
When using await for
method, I cannot pass new events to this bloc after SelectAddress
event:
if (event is SelectAddress) {
yield state.copyWith(isLoading: true);
try {
Stream<List<Store>> _storeListStream =
_databaseInterface.getNearbyStores(event.deliveryAddress, 5);
await for (List<Store> stores in _storeListStream) {
if (stores.isNotEmpty)
yield state.copyWith(
isLoading: false,
deliveryAddress: event.deliveryAddress,
isAddressSelected: true,
listOfStores: stores,
);
}
} catch (error) {
yield state.copyWith(isLoading: false, error: error);
}
}
I have a feeling I am not using the right approach.
Any help would be appreciated.
Hi @algirdasmac thanks for opening an issue!
Right off the bat, I wouldn't recommend creating a subscription directly in mapEventToState
because mapEventToState
gets called every time an event is dispatched. I would instead move all of the logic for getting nearby stores into a StoreRepository
and just expose a public getNearbyStores
which returns a Future
of nearby stores. Then in mapEventToState
you can do something like:
if (event is SelectAddress) {
yield state.copyWith(isLoading: true);
try {
List<Store> stores =
await _storeRepository.getNearbyStores(event.deliveryAddress, 5);
yield state.copyWith(
isLoading: false,
deliveryAddress: event.deliveryAddress,
isAddressSelected: true,
listOfStores: stores,
);
} catch (error) {
yield state.copyWith(isLoading: false, error: error);
}
}
If this answer doesn't make sense then:
Let me know if that helps! 馃憤
Thanks @felangel - you are always as fast as it can be - impressive!
Although this answer makes sense, it's just not what I am looking for. Unfortunately I can't give access to the repo (company policy), but I created simple flutter app with the situation:
https://github.com/algirdasmac/streams_and_blocs
In /lib/todo_bloc/todo_bloc.dart
I try to take stream results and add them to state. What I would try to do later is to listen to Firestore collection and show todo's to user (in case other user added some todo's).
I hope this is clear. If it is not - please do not hesitate to ask and I will try to explain even more. Thanks.
PS. I am looking more of an advice here, it should not be considered as an issue.
@algirdasmac no problem haha! I'll take a look shortly and will try to open a PR with some suggestion. 馃憤
@algirdasmac just opened a PR to connect the bloc to Firestore. Let me know if that helps!
Marking this as closed since it's more of a discussion at this point 馃槃
So simple and so effective. It is strange to me that I didn't think about it myself. Thanks @felangel !
I had exactly the same pb and this PR help me.
Question: This sample is using the previous State management implementation without "Equatable".
How easy it is to use the new Equatable solution to manage the state variables (todos) ?
Can you please update the sample ?
I have some difficulties to manage the different class to easily manage the variable (todos)
@fvisticot what sample are you referring to? Examples/flutter_todos?
I'm referring to https://github.com/algirdasmac/streams_and_blocs
I try to do the "same" thing with Firebase / Stream integration inside a bloc.
Would like to find a simple solution to manage Firebase data from Stream and Bloc/State
My "pb" is to manage the data (List
It's OK with todo sample code. Tx for your help.
@fvisticot Just want to confirm, you were able to solve your issue?
Yep, My issue is solved.
I'm using your solution with Todo sample.
My only "pb" was your solution to manage the updatedTodos
You only update this list in the state TodosLoaded
I was not sure if "else" cases can occurs
Most helpful comment
Yep, My issue is solved.
I'm using your solution with Todo sample.
My only "pb" was your solution to manage the updatedTodos
You only update this list in the state TodosLoaded
I was not sure if "else" cases can occurs