felangel / bloc

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

Tried to listen to an InheritedWidget in a life-cycle that will never be called again #1598

Closed raulmabe closed 4 years ago

raulmabe commented 4 years ago

Hello, I am coming from redux and I am learning how to use the BLoC pattern using flutter_bloc: ^6.0.1.

I am implementing an infinite list following this tutorial (with custom models) and I am getting the following error:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building MainPage(dirty):
flutter: Tried to listen to an InheritedWidget in a life-cycle that will never be called again.
flutter: This error typically happens when calling Provider.of with `listen` to `true`,
flutter: in a situation where listening to the provider doesn't make sense, such as:
flutter: - initState of a StatefulWidget
flutter: - the "create" callback of a provider
flutter:
flutter: This is undesired because these life-cycles are called only once in the
flutter: lifetime of a widget. As such, while `listen` is `true`, the widget has
flutter: no mean to handle the update scenario.
flutter:
flutter: To fix, consider:
flutter: - passing `listen: false` to `Provider.of`
flutter: - use a life-cycle that handles updates (like didChangeDependencies)
flutter: - use a provider that handles updates (like ProxyProvider).
flutter:
flutter: The relevant error-causing widget was:
flutter:   MainPage file:///app/lib/ui/home_page/home_page.dart:84:21

The error is thrown when trying to paint MainPage widget, which is the following widget:

class MainPage extends StatelessWidget {
  final ScrollController scrollController;

  MainPage({this.scrollController});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<AdsBloc, AdsState>(
      builder: (context, state) {
        if (state is AdsSuccess) {
          return _buildBody(context, state.category, state.paginatedAds.ads);
        }
        return _buildBody(context, state.category, []);
      },
    );
  }
}

When this widget is removed from the tree, the app does not crash. As I am new to BLoC, and also new to Provider, I can't find where is the bug. Any hint on the case will be highly appreciated.

felangel commented 4 years ago

Hi @Rahuvich 👋 Thanks for opening an issue!

Can you please share a link to a sample app which illustrates the problem you’re seeing? Thanks! 👍

raulmabe commented 4 years ago

Nevermind, the issue was I was calling MediaQuery.of(context) inside the create BlocProvider :sweat_smile: I thought it was a BLoC provider issue, but nope!

Thank you @felangel anyway for your great support to this library and to open source projects, Your presentation in Europe was very useful to us, newbies to BLoC :clap:

sidy-refyne commented 4 years ago

Just wanted to understand. why calling MediaQuery.of(context) inside creating the bloc is throwing the error. As I understand the context is BuildContext, which will have the access of the screen params. Calling it should work. rit?

BlocProvider(
          create: (context) {

            Map args = ModalRoute.of(context).settings.arguments;

            return  getIt<BaseBloc>()..add(BaseEvent.networkListeningInitiated()),
  })

As in this code trying to access the args is also throwing the same error.

narcodico commented 4 years ago

Hi @sidy-refyne 👋

You're getting that error simply because the inherited widget has no way of notifying the changes inside create since create is only called once, so basically it's an improper use of it.

MikiVanousek commented 2 years ago

You still may create a bloc with context, just make sure not to pass the Build context from the create method, but from previous methods. create: (_) => ClockScreenBloc(state, context)