Looking for great developers Looking for great developers [email protected]
Facebook Linkedin Dribbble Behance Cluth

Everything You Need to Know About BLoC State Manager in Flutter

20-04-2022 5 min read

Everything You Need to Know About BLoC State Manager in Flutter

Flutter lets you create a cross-platform app quickly. It is a widget-based solution to create UI and does not require using a bridge or native elements like React-Native. It speeds up development. But React-Native and Flutter have one thing in common: State Managing.

Flutter can support almost or every state management approach. It depends on the team/developer. One of them which is very popular is BLOC.

I appreciate these words. The acronym means "Business logic component." It means more than model-view-ViewModel (MVVM), but it is almost identical to a class diagram. Logic is just separated from the view, and UI observes the state.

Two crucial types for asynchronous programming

two crucial types for asynchronous programming

Dart programming language contains two crucial types for asynchronous programming. Stream and Future. Stream is a sequence of results, and a single computation represents the Future. Under the hood is based on streams.

Bloc is an abstract class extending Cubit. Cubit is simply a solution with an editing state on request. UI calls the method, and Cubit emits the new state. Bloc organizes this more formally. In Bloc, you have to override the mapEventToState(event) method. This method yields forms in response to an event.

class MovieBloc extends Bloc<MoviesEvent, MoviesState> {

  final MovieRepository _movieRepository;

  MovieBloc(MoviesState initialState, this._movieRepository)

      : super(initialState);

  @override

  Stream<MoviesState> mapEventToState(MoviesEvent event) async* {

    yield* event.map(

      trendingOption: (_) async* {

        yield MoviesState.loading();

        var option = await _movieRepository.allAsOption();

        yield option.fold(

          () => MoviesState.error(),

          (movies) => MoviesState.loaded(movies),

        );

      },

    );

  }

}

Compare it to Cubit:

class MovieCubit extends Cubit<MoviesState> {

  final MovieRepository repository;

  MovieCubit({this.repository}) : super(LoadingMovies());

  void getMoviesByOption() async {

    emit(LoadingMovies());

    final movies = await repository.allAsOption();

     movies.fold(

      (movies) => emit(LoadedMovies(movies)),

      (error) => emit(LoadedErrorTyped(error)),

    );

  }
} 

HydratedBloc and ReplayBloc libraries

HydratedBloc or ReplayBloc

Using it, you have probably heard about HydratedBloc or ReplayBloc. These libs are helpful in a quick delivery state to remember or replaying. It works in both Cubit and Bloc. You have two more methods to override hydrated: toJson() and fromJson(). In toJson(), you are just saving the interesting state, for example, a list of movies. And fromJson() decode it to state.

Replay comes in undo/redo functions.

You have a few Bloc-specific widgets on the UI to listen to state changes.

For example, BlocBuilder:

BlocBuilder<MovieBloc, MoviesState>(

        cubit: _movieBloc,

        builder: (context, state) {

          if (state is LoadedMovies) {

            return MoviesGrid(movies: state.movies);

          } else if (state is EmptyListOfMovies) {

            return EmptyListInfoSafeArea();

          } else if (state is LoadedError || state is LoadedErrorTyped) {

            return ErrorSafeArea();

          }

          return LoadingSafeArea();

        }, 

     ),

Types are what kind of Bloc it is and what kind of state it is generating.

Cubit just passed a reference to Bloc. It's a helpful tip not to generate Bloc on your UI page. I enjoy the get_it package, where you can easily manage your dependencies and inject what you need in your Bloc. Just call the dependency container to get one.

It very easily one-liner: final MovieBloc _movieBloc = getIt();

And MovieBloc comes in with injected repository (you need to define it on your container), as you can see.

  final MovieRepository _movieRepository;

 

  MovieBloc(MoviesState initialState, this._movieRepository)

      : super(initialState);

Testing of the Bloc is easy too

Testing of the Bloc

Like always, in Flutter space with an incredible community of pub.dev there is a superb transparent tool to test your Blocs. It is called Bloc_test.

So with MovieBloc, we inject a real movie repository that injects real data sources. So how do you test it and ensure the Bloc works well without making an actual network connection on any other third dependent stuff?

It's something I wrote a little in the article.

Bloc Test comes with an excellent structure for testing:

   blocTest(

      'emits [LoadingMovies, LoadedError] when repository return a none  from Option',

      build: () {

        when(mockRepository.allOption()).thenAnswer((_) async => none());

        return bloc;

      },

      act: (bloc) => bloc.add(LoadingMoviesByOption()),

      expect: [

        LoadingMovies(),

        LoadedError(),

      ],
    ); 

Build test with a mocked response. Act a blog bypassing event or request Cubit. And watch expected states.

Bloc is a great structured way to manage states in Flutter easily. To build native apps in record time - with a testable structure and changeable environment to pass your client's expectations. Comes with a great community like a Flutter. So I can thoroughly recommend it to your team.

About the author

Peter Koffer - Chief Technology Officer

With 13 years of experience in the IT industry and in-depth technical training, Peter could not be anything but our CTO. He had contact with every possible architecture and helped create many solutions for large and small companies. His daily duties include managing clients' projects, consulting on technical issues, and managing a team of highly qualified developers.

Contents

Start your project with us!
Peter Koffer - CTO

Let our people take your business to the next level.

Sounds interesting? Give us some details and get your free estimation.

Cookies.

By using this website, you automatically accept that we use cookies. What for?

Understood