Bloc: on<Event>, emit və handler qaydaları
Bloc — sənədin ifadəsi ilə state dəyişikliklərini funksiyalar yerinə event-lərlə tetikləyən daha inkişaf etmiş sinifdir. Struktur belədir:
- Event sinifləri elan olunur (adətən
sealed class+ alt siniflər). - Konstruktorda hər event tipi üçün handler qeyd olunur:
on<CounterIncrementPressed>((event, emit) => emit(state + 1)); - UI event əlavə edir:
context.read<CounterBloc>().add(CounterIncrementPressed()).
Handler-lər haqqında praktik qaydalar:
- Bir event tipi üçün bir handler qeyd olunur; eyni tip üçün ikinci
on<T>çağırışı səhvdir. emithandler-in daxilində,await-dən sonra da işləyir; lakin handler bitdikdən sonraemit-i saxlayıb istifadə etmək olmaz.- Stream-i state-ə çevirmək üçün
emit.forEachvəemit.onEachvar — abunəlik handler ilə birlikdə idarə olunur.
dart
// Event-lər keçmiş zamanda adlandırılır (rəsmi konvensiya).
sealed class TodoEvent {}
final class TodoStarted extends TodoEvent {}
final class TodoAdded extends TodoEvent {
TodoAdded(this.title);
final String title;
}
final class TodoDeleted extends TodoEvent {
TodoDeleted(this.id);
final String id;
}
class TodoBloc extends Bloc<TodoEvent, TodoState> {
TodoBloc(this._repository) : super(const TodoState()) {
on<TodoStarted>(_onStarted);
on<TodoAdded>(_onAdded);
on<TodoDeleted>(_onDeleted);
}
final TodoRepository _repository;
Future<void> _onStarted(TodoStarted event, Emitter<TodoState> emit) async {
emit(state.copyWith(status: TodoStatus.loading));
try {
final todos = await _repository.fetchAll();
emit(state.copyWith(status: TodoStatus.success, todos: todos));
} catch (error) {
emit(state.copyWith(status: TodoStatus.failure, error: '$error'));
}
}
Future<void> _onAdded(TodoAdded event, Emitter<TodoState> emit) async {
await _repository.create(event.title);
add(TodoStarted()); // yenidən yükləmə üçün event əlavə etmək məqbul yanaşmadır
}
Future<void> _onDeleted(TodoDeleted event, Emitter<TodoState> emit) async {
emit(state.copyWith(
todos: state.todos.where((t) => t.id != event.id).toList(),
));
await _repository.remove(event.id);
}
}Sealed event-lər, handler-lər və async iş.
dart
class ChatBloc extends Bloc<ChatEvent, ChatState> {
ChatBloc(this._repository) : super(const ChatState()) {
on<ChatSubscriptionRequested>(_onSubscriptionRequested);
}
final ChatRepository _repository;
Future<void> _onSubscriptionRequested(
ChatSubscriptionRequested event,
Emitter<ChatState> emit,
) async {
// Stream-in hər elementi state-ə çevrilir; abunəlik handler ilə
// birlikdə bağlanır — əl ilə StreamSubscription saxlamağa ehtiyac yoxdur.
await emit.forEach<List<Message>>(
_repository.watchMessages(),
onData: (messages) => state.copyWith(messages: messages),
onError: (error, stackTrace) => state.copyWith(error: '$error'),
);
}
}`emit.forEach` — stream-i state-ə çevirmək.
Rəsmi adlandırma konvensiyaları (böyük komandalar üçün xüsusilə tövsiyə olunur):
- Event-lər keçmiş zamanda adlandırılır, çünki bloc üçün onlar artıq baş vermiş hadisələrdir:
BlocSubject+ isim (opsional) + fel. İlk yükləmə event-i:BlocSubject+Started. Baza event sinfi:BlocSubject+Event. - State-lər isimdir, çünki state müəyyən andaki mənzərədir. Alt siniflərlə göstərildikdə:
BlocSubject+ fel +State, buradaState—Initial,Success,Failurevə yaInProgress.
📚 Mənbələr və sənədlər
- Bloc konseptlərirəsmibloclibrary.dev
on<Event>, Emitter, emit.forEach və Cubit/Bloc fərqi.
- Adlandırma konvensiyalarırəsmibloclibrary.dev
Event və state adlandırmasının rəsmi qaydaları — code review-da istinad nöqtəsi.
- Bloc arxitekturasırəsmibloclibrary.dev
- package:blocrəsmipub.dev