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)