felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.73k stars 3.38k forks source link

[feature request] Ability to provide bloc in BlocBuilder / BlocConsumer #2130

Closed cedvdb closed 3 years ago

cedvdb commented 3 years ago

Is your feature request related to a problem? Please describe. I would like to avoid nesting unnecessarily by having a BlocProvider + a Bloc Consumer for screens cubit. This would make the use leaner of the UI.

Describe the solution you'd like instead of this

            BlocProvider(
              create: (ctx) => PhoneFormBloc(),
              child: BlocConsumer<PhoneFormBloc, FormxState>( 
                builder: (context, state) => PhoneForm(
                        onSubmit: context.read<PhoneFormBloc>().submit,
               )

Having this:

            BlocConsumer<PhoneFormBloc, FormxState>(
              cubit: PhoneFormBloc(),
              builder: (context, state) => PhoneForm(
                    onSubmit: context.read<PhoneFormBloc>().submit,
               )

or

            BlocConsumer<PhoneFormBloc, FormxState>(
                create: (ctx) => PhoneFormBloc(),
                builder: (context, state) => PhoneForm(
                        onSubmit: context.read<PhoneFormBloc>().submit,
                )
felangel commented 3 years ago

Hi @cedvdb 👋 Thanks for opening an issue!

I would highly recommend against this because it results in tightly coupling the widget which is creating the bloc with the widget that is consuming the bloc. This makes it extremely difficult to write widget tests because they will be using the real bloc and it's not possible to provide a mock.

For an example, you can refer to the weather example and note that the role of the WeatherPage is to provide an instance of a WeatherCubit to the WeatherView. Then the WeatherView is just consuming the cubit state and has no idea where it came from.

We can then test the WeatherView very easily by providing a Mock instance of the WeatherCubit.

Hope that helps 👍

cedvdb commented 3 years ago

I see, good observation as always. Annotations would be nice (without a builder) though .

Closing

cedvdb commented 3 years ago

@felangel Do you see any drawbacks of doing it like this (and bubbling everything to the top):

class PreferencesScreen extends StatelessWidget {
  final PreferencesBloc _preferencesBloc = PreferencesBloc();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: SentAppBar(
      body: BlocBuilder<PreferencesBloc, FormxState>(
        bloc: _preferencesBloc,
        builder: (ctx, state) => state is FormxStateForm
            ? PreferencesForm(
                value: state.initialValue,
                onChange: (value) => _preferencesBloc.submit(value),
              )
            : Spinner(),
      ),
    );
  }
}
felangel commented 3 years ago

@cedvdb yes, you should avoid doing that because the bloc will never be disposed properly.