Bloc: Error when using BlocProvider.of

Created on 20 Oct 2019  Β·  1Comment  Β·  Source: felangel/bloc

Hi, I have a problem regarding the BlocProvider.of(context) method.

I created a small test app with the following main.dart file

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TestWidget(),
    );
  }
}

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<TestBloc>(
      builder: (BuildContext context) => TestBloc(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('Test'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.add_circle_outline),
              onPressed: () {
                BlocProvider.of<TestBloc>(context).add(TestEvent.event2);
              },
            )
          ],
        ),
      ),
    );
  }
}

enum TestEvent {
  event1,
  event2
}

enum TestState {
  state1, 
  state2
}

class TestBloc extends Bloc<TestEvent, TestState> {
  @override
  TestState get initialState => TestState.state1;

  @override
  Stream<TestState> mapEventToState(TestEvent event) async* {
    if (event == TestEvent.event1) {
      yield TestState.state1;
    } else {
      yield TestState.state2;
    }
  }
}

When clicking the button, the following error is thrown:

No ancestor could be found starting from the context that was passed to BlocProvider.of<TestBloc>().

        This can happen if:
        1. The context you used comes from a widget above the BlocProvider.
        2. You used MultiBlocProvider and didn't explicity provide the BlocProvider types.

        Good: BlocProvider<TestBloc>(builder: (context) => TestBloc())
        Bad: BlocProvider(builder: (context) => TestBloc()).

        The context used was: TestWidget

When the exception was thrown, this was the stack
#0      BlocProvider.of 
package:flutter_bloc/src/bloc_provider.dart:80
#1      TestWidget.build.<anonymous closure> 
package:flutter_bloc_issue/main.dart:28
#2      _InkResponseState._handleTap 
package:flutter/…/material/ink_well.dart:654
#3      _InkResponseState.build.<anonymous closure> 
package:flutter/…/material/ink_well.dart:729
#4      GestureRecognizer.invokeCallback 
package:flutter/…/gestures/recognizer.dart:182
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#02b38
    debugOwner: GestureDetector
    state: possible
    won arena
    finalPosition: Offset(391.7, 72.3)
    finalLocalPosition: Offset(25.7, 28.3)
    sent tap down
════════════════════════════════════════════════════════════════════════════════

Am I doing something wrong?

Thanks in advance for your help!

question

Most helpful comment

Hi @hoi4 πŸ‘‹
Thanks for opening an issue!

The problem is you’re trying to access BlocProvider from the same context in which it was instantiated. I would recommend wrapping TestWidget in the BlocProvider instead.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider<TestBloc>(
        builder: (context) => TestBloc(),
        child: TestWidget(),
    );
  }
}

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.add_circle_outline),
            onPressed: () => BlocProvider.of<TestBloc>(context).add(TestEvent.event2),
          ),
        ],
      ),
    );
  }
}

Hope that helps πŸ‘

>All comments

Hi @hoi4 πŸ‘‹
Thanks for opening an issue!

The problem is you’re trying to access BlocProvider from the same context in which it was instantiated. I would recommend wrapping TestWidget in the BlocProvider instead.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider<TestBloc>(
        builder: (context) => TestBloc(),
        child: TestWidget(),
    );
  }
}

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.add_circle_outline),
            onPressed: () => BlocProvider.of<TestBloc>(context).add(TestEvent.event2),
          ),
        ],
      ),
    );
  }
}

Hope that helps πŸ‘

Was this page helpful?
0 / 5 - 0 ratings