事件管理颤振块模式

时间:2021-05-27 03:19:06

标签: flutter dart events bloc

大家。我是 Flutter 和 BLoC 模式的新手。

我需要实现联系人页面,所以我创建了事件 GetContacts 并将其传递给 context.read().add() 之后,我将此事件调用到联系人屏幕的 initState() 中。

这是我的活动:


abstract class ContactEvent extends Equatable {
  const ContactEvent([List props = const []]) : super();
}

class GetContacts extends ContactEvent {

  const GetContacts() : super();

  @override
  List<Object> get props => [];
} 

这是我的集团:

class ContactsBloc extends Bloc<ContactEvent, ContactsState> {
  final ContactsRepo contactsRepo;
  ContactsBloc({required this.contactsRepo}) : super(ContactInitial());

  @override
  Stream<ContactsState> mapEventToState(ContactEvent event,) async* {
    yield ContactsLoading();
    //
    // if (event is UpdatePhoto) {
    //   yield PhotoLoading();
    //
    //   print("LOADING STARTED");
    //
    //   final photo = await contactsRepo.updatePhoto(event.identifier, event.photo);
    //   print("LOADING FINISHED");
    //
    //   yield PhotoLoaded(photo: photo);
    // }
    if (event is GetContacts) {
      print("get contacts photoBloc");
      try {

        final contacts = await contactsRepo.getContacts();
        yield ContactsLoaded(contacts);
      } on AccessException {
        yield ContactsError();
      }
    }
  }
} 

效果很好,联系人页面会按预期呈现联系人。

[联系人屏幕][1] [1]:https://i.stack.imgur.com/Gx3JA.png

但后来我决定实施新功能:当用户点击任何联系人时,他会被要求更改其照片。 如果我正确理解 BLoC 模式,那么如果我想改变我的状态,我需要创建新事件。然后我创建了新的操作 UpdatePhoto 并将它传递到同一个 Bloc 中,正如它在代码的第二部分(在注释中)所示。正是在那里,我遇到了对架构扩展的误解。此操作不应返回 ContactsLoaded 状态,因此当我尝试将其捕获到我的另一个 bloc 构建器中时,它破坏了我之前捕获 GetContact 事件的 bloc 构建器。

联系状态:

abstract class ContactsState extends Equatable {
  const ContactsState([List props = const []]) : super();
}


// class PhotoLoading extends PhotoState {
//   @override
//   List<Object?> get props => [];
// }
//
// class PhotoLoaded extends PhotoState {
//   final Uint8List photo;
//   const PhotoLoaded({required this.photo});
//   @override
//   List<Object?> get props => [photo];
// }

class ContactInitial extends ContactsState {
  @override
  List<Object> get props => [];
}

class ContactsLoading extends ContactsState {
  @override
  List<Object> get props => [];
}

class ContactsLoaded extends ContactsState {
  final List<MyContact> contacts;
  ContactsLoaded(this.contacts) : super([contacts]);

  @override
  List<Object> get props => [contacts];
}

class ContactsError extends ContactsState {
  @override
  List<Object?> get props => [];
}

问题:如果我想创建新事件(例如 UpdatePhoto),该事件不应该返回我之前在同一块中捕获的状态,那么我需要为此目的创建新块并通过 multiProvider 覆盖我的屏幕?

2 个答案:

答案 0 :(得分:2)

您还应该发布您的 ContactState 代码。

然而,你并不一定需要一个新的 Bloc。这一切都取决于您要实现的目标。 我想当你 yield PhotoLoading() 你想要展示一个加载器时。 但是,当您更新照片时,如果我了解您要实现的目标,您应该再次使用 yield ContactsLoaded(contacts)add(GetContacts()) 而不是 yield PhotoLoaded(photo: photo) 生成更新的联系人列表。 如果您想显示确认消息,您可以保持 PhotoLoaded 状态,但您需要在构建 UI 时考虑到 bloc 可能发出的不同状态。

请记住,在 BloC 架构中,事件可以连续产生多个状态,而 UI 决定是否以及如何对每个状态做出反应。

答案 1 :(得分:1)

我想在 BlocBuilder 中使用可选参数 buildWhen 是避免为每个事件创建新 bloc 的最佳方法。