Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Bloc : No ancestor could be found starting from the context?

Tags:

flutter

I'm new to Flutter, and also new to Bloc use.

I have an error when compiling the code:

    The following assertion was thrown building Login(dirty, state: _LoginFormState#44e7f):
         BlocProvider.of() called with a context that does not contain a Bloc of type BtnBloc.
         No ancestor could be found starting from the context that was passed to
         BlocProvider.of<BtnBloc>().
       This can happen if the context you use comes from a widget above the BlocProvider.
         This can also happen if you used BlocProviderTree and didn't explicity provide 
         the BlocProvider types: BlocProvider(bloc: BtnBloc()) instead of BlocProvider<BtnBloc>(bloc:
         BtnBloc()).
         The context used was: Login(dirty, state: _LoginFormState#44e7f)    

I've tried to change some stuff in my bloc class, but nothing does about it.

Here is my blog class :

class BtnBloc extends Bloc<BtnEvent, BtnState> {
  @override
  BtnState get initialState => BtnState.initial();

  @override
  Stream<BtnState> mapEventToState(
      BtnState currentState, BtnEvent event) async* {
    if (event is IdleEvent) {
      yield currentState..state = 1;
    } else if (event is LoadingEvent) {
      yield currentState..state = 1;
    } else if (event is RevealEvent) {
      yield currentState..state = 2;
    }
  }
}

And here is my build method :

final _btnBloc = new BtnBloc();

  _LoginFormState(
      {Key key,
      this.primaryColor,
      this.backgroundColor,
      this.backgroundImage,
      this.logo});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
        bloc: _btnBloc,
        child: BlocBuilder<BtnEvent, BtnState>(
            bloc: BlocProvider.of<BtnBloc>(context),
            builder: (context, BtnState state) {
return myWidget();

Please help me :'(

like image 743
Vincent Guillois Avatar asked Mar 25 '19 08:03

Vincent Guillois


2 Answers

After the while of time facing this problem, I hope this article will help you to understand more about context. The general solution is the same as the @Filled Stacks's answer. It means that you have to pass the bloc when navigating into a new page, so the BlocProvider can find which type of Bloc you will be received.

I recommend initing the main function for the overall application which will init your screens and context through the screens. For eg:

  • Init and passing Bloc:
class ListTodoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<TodoBloc>(
        create: (context) => TodoBloc(TodoDao())..add(QueryTodoEvent()),
        child: ListTodoPageful());
  }
}

class ListTodoPageful extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return ListTodoState();
  }
}

class ListTodoState extends State<ListTodoPageful> {
  TodoBloc _todoBloc;
  @override
  Widget build(BuildContext context) {
    _todoBloc = BlocProvider.of<TodoBloc>(
        context);
   //...
   floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
              context,
              CupertinoPageRoute(
                  builder: (context) => BlocProvider.value(
                      value: _todoBloc, child: CreateTaskPage())));
        }
  //...
}
  • Receive Bloc:
class _CreatePageState extends State<CreateTaskPage> {
  TodoBloc _todoBloc;

  @override
  Widget build(BuildContext context) {
    _todoBloc = BlocProvider.of<TodoBloc>(context);
}

Refer to my sample application here: https://github.com/huynguyennovem/flutter_todo

like image 172
Huy Nguyen Avatar answered Nov 02 '22 20:11

Huy Nguyen


The line below is your problem. The error is exactly what the message says.

...
child: BlocBuilder<BtnEvent, BtnState>(
     bloc: BlocProvider.of<BtnBloc>(context), <------- Problem line
     builder: (context, BtnState state) {
...

The context you're using there does not have a BlocBuilder attached to it so nothing is passing the BloC down from the top to your LoginState. You can either

  1. Use your existing bloc (_btnBloc) and pass it in (recommended)
  2. Wrap the widget putting the LoginState on screen with a BlocProvider so that you have access to it in the widget state.

If this is your first view then use 1.

Change

 bloc: BlocProvider.of<BtnBloc>(context), <------- Problem line

To

bloc: _btnBloc
like image 5
Filled Stacks Avatar answered Nov 02 '22 20:11

Filled Stacks