Reputation: 1937
Let's assume we have an app where user has a calendar where he can select a date for which he wants to get list of events. When user selects the date, we add an event CalendarSelectedDateChanged(DateTime)
. Bloc component fetches data from API each time we receive such an event. We can imagine a situation when the response is received with different delay. This will produce the following scenario:
Expected result is that we discard response from request date=1 here
How can we resolve such a race condition in the most elegant way (preferably for all BLoCs in the app at once)?
Here's an exemplary code that will produce such an issue:
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc()
: super(ExampleDataLoadInProgress(DateTime.now())) {
on<ExampleSelectedDateChanged>((event, emit) async {
await _fetchData(event.date, emit);
});
}
Future<void> _fetchData(DateTime selectedDate,
Emitter<ExampleState> emit,) async {
emit(ExampleDataLoadInProgress(selectedDateTime));
try {
final data = callAPI(selectedDateTime);
emit(ExampleDataLoadSuccess(data, selectedDate));
} on ApiException catch (e) {
emit(ExampleDataLoadFailure(e, selectedDateTime));
}
}
}
Upvotes: 4
Views: 1970
Reputation: 1937
By default all events are processed concurrently, you can change that behavior by setting a custom transformer:
You can read more about transformers here: https://pub.dev/packages/bloc_concurrency
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc()
: super(ExampleDataLoadInProgress(DateTime.now())) {
on<ExampleSelectedDateChanged>((event, emit) async {
await _fetchData(event.date, emit);
},
transformer: restartable(), // ADD THIS LINE
);
}
Future<void> _fetchData(DateTime selectedDate,
Emitter<ExampleState> emit,) async {
emit(ExampleDataLoadInProgress(selectedDateTime));
try {
final data = callAPI(selectedDateTime);
emit(ExampleDataLoadSuccess(data, selectedDate));
} on ApiException catch (e) {
emit(ExampleDataLoadFailure(e, selectedDateTime));
}
}
}
Upvotes: 6