Bloc: Could you make initialState getter support async operations?

Created on 9 Dec 2019  路  1Comment  路  Source: felangel/bloc

Is your feature request related to a problem? Please describe.
I tried to implement a settings screen with a couple of switches, where the value of the switches would come from SharedPreferences. I tried to implement as much of the code as possible to be async but I had a problem initialising my blocs from the async methods.

Right now I declare the initial state of the bloc/switch as off and I add an event to load the state from the preferences. This event is handled by mapEventToState function properly, but with this solution I can see the switch of for a fraction of a second which I consider quite ugly.

Describe the solution you'd like
To have a possibilty to use async functions to initialise the bloc state. Or if it is possible right now please provide an example for this.

question

Most helpful comment

Hi @kozmabalazs 馃憢
Thanks for opening an issue!

The whole idea of bloc is that the initialState must be sync because there must be an initial state immediately available when the bloc is instantiated.

I would recommend having a setup like:

class MyBloc extends Bloc<MyEvent, MyState> {
  @override
  MyState get initialState => Loading();

  @override
  Stream<MyState> mapEventToState(MyEvent event) async* {
    if (event is Started) {
      final settings = await _getSettingsFromSharedPreferences();
      yield Loaded(settings);
    }
  }
}

Then when you create the bloc using BlocProvider you can immediately add the Started event like so:

BlocProvider<MyBloc>(
  create: (_) => MyBloc()..add(Started()),
  child: MyChild(),
)

And you can show a splash screen or loading indicator until the data is loaded:

BlocBuilder<MyBloc, MyState>(
  builder: (context, state) {
    if (state is Loaded) {
      return Home(state.settings);
    }
    return SplashScreen();
  }
)

Hope that helps 馃憤

>All comments

Hi @kozmabalazs 馃憢
Thanks for opening an issue!

The whole idea of bloc is that the initialState must be sync because there must be an initial state immediately available when the bloc is instantiated.

I would recommend having a setup like:

class MyBloc extends Bloc<MyEvent, MyState> {
  @override
  MyState get initialState => Loading();

  @override
  Stream<MyState> mapEventToState(MyEvent event) async* {
    if (event is Started) {
      final settings = await _getSettingsFromSharedPreferences();
      yield Loaded(settings);
    }
  }
}

Then when you create the bloc using BlocProvider you can immediately add the Started event like so:

BlocProvider<MyBloc>(
  create: (_) => MyBloc()..add(Started()),
  child: MyChild(),
)

And you can show a splash screen or loading indicator until the data is loaded:

BlocBuilder<MyBloc, MyState>(
  builder: (context, state) {
    if (state is Loaded) {
      return Home(state.settings);
    }
    return SplashScreen();
  }
)

Hope that helps 馃憤

Was this page helpful?
0 / 5 - 0 ratings