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

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

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

Tags:

Flutter