Suhas Shelar
Suhas Shelar

Reputation: 983

Flutter - Transform flutter bloc event to add debounce

I am trying to make an Infinite list using flutter bloc.

I have taken reference from here: https://github.com/felangel/bloc/blob/926029cae2d7614d38b5a9a8952e36bb59054b02/examples/github_search/common_github_search/lib/src/github_search_bloc/github_search_bloc.dart#L15

According to this post, to add a delay between two events so that api doesn't get spammed, you need to override transformEvents and add debounce to events like this:

@override
  Stream<GithubSearchState> transformEvents(
    Stream<GithubSearchEvent> events,
    Stream<GithubSearchState> Function(GithubSearchEvent event) next,
  ) {
    return (events as Observable<GithubSearchEvent>)
        .debounceTime(
          Duration(milliseconds: 300),
        )
        .switchMap(next);
  }

Problem I am facing is that the Observable has been deprecated by RxDart and I am not sure how to accomplish the above requirement.

Upvotes: 4

Views: 18010

Answers (4)

Rissmon Suresh
Rissmon Suresh

Reputation: 14083

I had a similar issue and I could solve it by adding the below imports

import 'package:stream_transform/stream_transform.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

Then we can provide a custom EventTransformer to change the way the Bloc processes incoming events.

EventTransformer<T> debounce<T>(Duration duration) {
  return (events, mapper) => events.debounceTime(duration).flatMap(mapper);
}

Now we would probably want to debounce the requests to the backend to avoid getting rate-limited and cut down on cost/load on the backend.

CounterBloc() : super(0) {
  on<Increment>(
    (event, emit) => emit(state + 1),
    /// Apply the custom `EventTransformer` to the `EventHandler`.
    transformer: debounce(const Duration(milliseconds: 300)),
  );
}

Note: I was using flutter_bloc: ^8.1.1

Upvotes: 1

user2220771
user2220771

Reputation: 459

Since bloc 8.0.0 the syntax changed and you need to pass it as a transformer to the on function. Apart from the debouncing you should think about concurrency. To combine sequential processing with a debounce, you can provide the following function:

import 'package:rxdart/rxdart.dart';
//...

    on<GithubSearchEvent>(
      (event, emit) {},
      transformer: (events, mapper) {
        return events.debounceTime(const Duration(milliseconds: 300)).asyncExpand(mapper);
      },
    );

You can create a reusable transformer as a top-level function like this:

EventTransformer<Event> debounceSequential<Event>(Duration duration) {
  return (events, mapper) => events.debounceTime(duration).asyncExpand(mapper);
}

and use it like this:

    on<GithubSearchEvent>(
      (event, emit) {},
      transformer: debounceSequential(const Duration(milliseconds: 300)),
    );

Upvotes: 23

Thioby
Thioby

Reputation: 196

I cannt add comment to @user2220771 cause my reputation is too low.

This will not work:

EventTransformer<Event> debounceTransformer<Event>(Duration duration) {
  return (events, mapper) => events.debounceTime(duration);
}

you have to switch map as:

EventTransformer<Event> debounceTransformer<Event>(Duration duration) {
  return (events, mapper) {
    return events.debounceTime(duration).switchMap(mapper);
  };
}

Upvotes: 8

Suhas Shelar
Suhas Shelar

Reputation: 983

I found the solution.

@override
  Stream<Transition< GithubSearchEvent, GithubSearchState >> transformEvents(
      Stream< GithubSearchEvent > events, transitionFn) {
    return events
        .debounceTime(const Duration(milliseconds: 300))
        .switchMap((transitionFn));
  }

Upvotes: 12

Related Questions