Home > Enterprise >  Could not find the correct Provider<TokenBloc> above this App Widget
Could not find the correct Provider<TokenBloc> above this App Widget

Time:05-17

I using BLoC. How to create it correctly, what would not arise due to the lack of widgets down the widget tree. Now I usually like this:

    Widget build(BuildContext context) {
return MaterialApp(
    // debugShowCheckedModeBanner: false,
    theme: Styles.appTheme,

    home: BlocProvider<TokenBloc>(
      create: (context) => di.sl<TokenBloc>(),
      child: _childTokenBloc,
    ),
  );
}


   

 Widget get _childTokenBloc {
      return BlocBuilder<TokenBloc, TokenState>(builder: (context, state) {
        if (state is TokenInitialState) {
          context.read<TokenBloc>().add(TokenCheckEvent());
          return const LogoImage();
        }
        if (state is TokenCheckState) {
          return const LogoImage();
        }
    
        if (state is TokenOkState) {
          return MainPageWidget();
        }
    
        if (state is TokenNoAuthorizationState) {
          return const AuthorizationPageWidget();
        }
        return const LogoImage();
      }
      );
    }

In AuthorizationPageWidget I do:

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const ConfirmAuthorizationPage()),
);

And from ConfirmAuthorizationPage I try to turn to TokenBloc:

context.read<TokenBloc>().add(TokenAddEvent());

but I get Error: Could not find the correct Provider above this App Widget

I thought that TokenBloc would be found in the widget tree, but is it not? And how to fix this problem? Need to use MultiBlocProvider in the build method of the ConfirmAuthorizationPage widget? It will be re-initialized, and the previous one will not be used.


Update 1: Code AuthorizationPageWidget:

class AuthorizationPageWidget extends StatefulWidget {
  const AuthorizationPageWidget({Key? key}) : super(key: key);

  @override
  _AuthorizationPageWidgetState createState() =>
      _AuthorizationPageWidgetState();
}

class _AuthorizationPageWidgetState extends State<AuthorizationPageWidget> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider<AuthorizationBloc>(
        create: (context) => sl<AuthorizationBloc>(),
        child: SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _title,
                _description,
                Expanded(child: Align(alignment: FractionalOffset.bottomCenter, child: _bottomButton))
              ],
            ),
        ),
      ),
    );
  }


//......   

 
void pushConfirmPage(String number) {

    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => ConfirmAuthorizationPage(number: number,)),
    );
  }
}

CodePudding user response:

If you want to provide your Bloc in all your application, you have to write it in your MaterialApp like this, not in the body ;

return 
    BlocProvider<TokenBloc>( // like this
       create: (context) => TokenBloc(),
       child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Flutter Demo',
          home: _TokenHome(),
       ),
    ),
);

class _TokenHome extends StatelessWidget { // use a class instead of function
  const _TokenHome({
    Key? key,
  }) : super(key: key);

@override
  Widget build(BuildContext context) {
    return BlocBuilder<TokenBloc, TokenState>(
      builder: (context, state) {
          if (state is TokenInitialState) {
            context.read<TokenBloc>().add(TokenCheckEvent());
            return const LogoImage();
          }
          if (state is TokenCheckState) {
            return const LogoImage();
          }
          if (state is TokenOkState) {
            return MainPageWidget();
          }
          if (state is TokenNoAuthorizationState) {
            return const AuthorizationPageWidget();
          }
          return Container(
            width: 50,
            height: 50,
            color: Colors.red,
          ); // use this if there is not a state
        }
    );
  }
}

If for some reason it doesn't show anything anymore, then it's because some of your classes like AuthorizationPageWidget or LogoImage are wrong, check that.

-------- EDIT

Using BlocProvider on each page can be useful, but keep in mind that for example AuthorizationBloc will only work for its children, if you call it on another side of the screen it will not work, so it is highly recommended to use a MultiBlocProvider in MaterialApp to avoid future problems;

return MultiBlocProvider( // like this
  providers: [
    BlocProvider<TokenBloc>(
      create: (context) => TokenBloc(),
    ),
    BlocProvider<AuthorizationBloc>(
      create: (context) => AuthorizationBloc(),
    ),
  ],
  child: BlocBuilder<LanguageCubit, Locale?>(
    builder: (context, lang) {
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
      );
    },
  ),
);

So all the other BlocProvider that you use to create, delete them, you do not need them, now if you use a BlocBuilder, BlocListeners of any Bloc, you would not have any inconvenience.

  • Related