Convert Default Flutter_bloc 8.0 Counter from Cubit to Bloc

Issue

I’m trying to convert bloc’s simple cubit example to the bloc pattern but getting an ...NoSuchMethodError: Class '_Emitter<MyObjectState>... error when I press the increment button.

I believe my problem is the dynamic type I used for the emit parameter (changing it to MyObjectState results in an error that the expression isn’t a function).

What should that be, and is that my only issue?

class MyObjectBloc extends Bloc<MyObjectEvent, MyObjectState> {
  MyObjectBloc() : super(const MyObjectState(counter: 99)) {
    on<AddEvent>(_onIncrement);
    on<SubtractEvent>(_onDecrement);
  }

  void _onIncrement(AddEvent event, dynamic emit) => emit(counter: state.counter + 1);
  void _onDecrement(SubtractEvent event, dynamic emit) => emit(counter: state.counter - 1);
  }

  abstract class MyObjectEvent {
    const MyObjectEvent();
  }
  class AddEvent extends MyObjectEvent {}
  class SubtractEvent extends MyObjectEvent {}

 class MyObjectState {
   const MyObjectState({required this.counter});
   final int counter;
 }


class CounterPage extends StatelessWidget {
  const CounterPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => MyObjectBloc(),
      child: CounterView(),
    );
  }
}

class CounterView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      body: Center(
        child: BlocBuilder<MyObjectBloc, MyObjectState>(
          builder: (context, state) {
            return Text('${state.counter}', style: textTheme.headline2);
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.add),
            onPressed: () => context.read<MyObjectBloc>().add(AddEvent()),
          ),
          FloatingActionButton(
            child: const Icon(Icons.remove),
            onPressed: () => context.read<MyObjectBloc>().add(SubtractEvent()),
          ),
        ],
      ),
    );
  }
}

Solution

The problem here is your emit is wrong.

TLDR answer

class MyObjectBloc extends Bloc<MyObjectEvent, MyObjectState> {
  MyObjectBloc() : super(const MyObjectState(counter: 99)) {
    on<AddEvent>(_onIncrement);
    on<SubtractEvent>(_onDecrement);
  }

  void _onIncrement(AddEvent event, Emitter<MyObjectState> emit) => emit(MyObjectState(counter: state.counter + 1));
  void _onDecrement(SubtractEvent event, Emitter<MyObjectState> emit) => emit(MyObjectState(counter: state.counter - 1));
}

abstract class MyObjectEvent {
  const MyObjectEvent();
}
class AddEvent extends MyObjectEvent {}
class SubtractEvent extends MyObjectEvent {}

class MyObjectState {
  const MyObjectState({required this.counter});
  final int counter;
}

Explanation

If we take a closer look at on<EVENT>, it is a function of:

  void on<E extends Event>(
    EventHandler<E, State> handler, {
    EventTransformer<E>? transformer,
  })

the first argument is EventHandler<E, State> which is:

typedef EventHandler<Event, State> = FutureOr<void> Function(
  Event event,
  Emitter<State> emit,
);

so you should emit your state class.

Answered By – yuzuriha

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.