0

This is an example of a Flutter counter app. I instantiate the Counter with a Bloc like this:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Counter(CounterBloc()),
    );
  }
}

This code below works fine. Event is dispatched and the "builder" method is called.

class Counter extends StatelessWidget {
  final Bloc bloc;

  const Counter(this.bloc, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (context) => bloc,
      child: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<CounterBloc, int>(
        builder: (context, count) => CountView(count),
      ),
      floatingActionButton: AddButton(
          action: () => BlocProvider.of<CounterBloc>(context)
              .add(CounterEvent.increment)),
    );
  }
}

The code below does not work. The event is dispatched but the builder is never called.

class Counter extends StatelessWidget {
  final Bloc bloc;

  const Counter(this.bloc, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (context) => bloc,
      child: Scaffold(
        body: BlocBuilder<CounterBloc, int>(
          builder: (context, count) => CountView(count),
        ),
        floatingActionButton: AddButton(
            action: () => BlocProvider.of<CounterBloc>(context)
                .add(CounterEvent.increment)),
      ),
    );
  }
}

I found out that I can set property "bloc" on a "BlocBuilder" but I'd expect it's not necessary. Why the difference in behavior?

N'joy Y'ventr
  • 172
  • 2
  • 9

1 Answers1

0

I believe the CounterEvent.increment from not working snippet won't get dispatched and instead will throw an error BlocProvider.of() called with a context ... because you use the same context where you provided the bloc.

This code works because it's a new context after BlocProvider

class Counter extends StatelessWidget {
  final Bloc bloc;

  const Counter(this.bloc, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (context) => bloc,
      child: Builder(
        builder: (context) => Scaffold(
          body: BlocBuilder<CounterBloc, int>(
            builder: (context, count) => CountView(count),
          ),
          floatingActionButton: AddButton(
            action: () => BlocProvider.of<CounterBloc>(context)
                .add(CounterEvent.increment),
          ),
        ),
      ),
    );
  }
}

This code also works because we explicitly use the bloc instance from the constructor instead of calling BlocProvider.of() and using the bloc instance provided via BlocProvider.

class Counter extends StatelessWidget {
  final Bloc bloc;

  const Counter(this.bloc, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (context) => bloc,
      child: Scaffold(
        body: BlocBuilder<CounterBloc, int>(
          bloc: bloc,
          builder: (context, count) => CountView(count),
        ),
        floatingActionButton: AddButton(
          action: () => bloc.add(CounterEvent.increment),
        ),
      ),
    );
  }
}

Both snippets above will work but it's not exactly the "correct" way.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Counter(
        CounterBloc(), // <=() You need a work around to dispose this instance
      ),
    );
  }
}
Federick Jonathan
  • 2,726
  • 2
  • 13
  • 26