【问题标题】:Can't update BLoC state with asynchronously received data无法使用异步接收的数据更新 BLoC 状态
【发布时间】:2021-04-13 06:12:39
【问题描述】:

我将在 firebase 商店中创建 Photo 实体,我需要获取两个字段,例如当前用户的电子邮件和 Photo url,但我的 BLoC 不会使用异步接收的数据更新状态。这是我的代码

  saved: (e) async* {
    Either<PhotoFailure, Unit> failureOrSuccess;
    final userOption = await _authFacade.getSignedInUser();
    final user = userOption.fold(() => null, (user) => user);
    print(user.emailAddress.getOrCrash());
    yield state.copyWith(
        photo:
            state.photo.copyWith(author: user.emailAddress.getOrCrash()));
    print(state.photo.author);
    yield state.copyWith(
        photo: state.photo.copyWith(
            uploadDate: DateFormat("dd-MM-yyyy").format(DateTime.now())));
    print(state.photo.uploadDate);
    FirebaseStorage _storage = FirebaseStorage.instance;
    Reference _rootReference = _storage.ref().child('photos');
    UploadTask task = _rootReference.putFile(state.photoFile);
    String downloadUrl = await (await task).ref.getDownloadURL();
    print(downloadUrl);
    yield state.copyWith(
      photo: state.photo.copyWith(url: downloadUrl),
    );
    print(state.photo.url);

    yield state.copyWith(
      isSaving: true,
      saveFailureOrSuccessOption: none(),
    );

    if (state.photo.failureOption.isNone()) {
      state.isEditing
          ? await _photoRepository.update(state.photo)
          : await _photoRepository.create(state.photo);
    }

    yield state.copyWith(
      isSaving: false,
      showErrorMessages: AutovalidateMode.always,
      saveFailureOrSuccessOption: optionOf(failureOrSuccess),
    );
  },
);

}

如您所见,我决定打印所有结果并在控制台记录此

I/flutter (19212): test@gmail.com
I/flutter (19212): 
I/flutter (19212): 2021-01-07 16:47:23.279989
D/UploadTask(19212): Increasing chunk size to 524288
I/flutter (19212): https://firebasestorage.googleapis.com/v0/b/simplefirebasegalley.appspot.com/o/photos?alt=media&token=73b3537f-d36c-49a8-b080-5cd27837c50e
I/flutter (19212):

所以我得到了正确的数据,但我不能只用异步数据更新状态,因为 uploadDate 工作正常。

我的州代码

@freezed
 abstract class PhotoFormState with _$PhotoFormState {
   const factory PhotoFormState({
     @required Photo photo,
     @nullable @required File photoFile,
     @required AutovalidateMode showErrorMessages,
     @required bool isEditing,
     @required bool isSaving,
     @required Option<Either<PhotoFailure, Unit>> saveFailureOrSuccessOption,
     }) = _PhotoFormState;

   factory PhotoFormState.initial() => PhotoFormState(
       photo: Photo.empty(),
       photoFile: null,
       showErrorMessages: AutovalidateMode.disabled,
       isEditing: false,
       isSaving: false,
       saveFailureOrSuccessOption: none(),
       );
 }

这是我的照片实体类

@freezed
 abstract class Photo with _$Photo {
   const Photo._();

   const factory Photo({
     @required String url,
     @required String type,
     @required int watchCount,
     @required UniqueId id,
     @required PhotoName name,
     @required PhotoDescription description,
     @required TagList<Tag> tagList,
     @required String author,
     @required String uploadDate,
     @required FieldValue serverTimeStamp,
   }) = _Photo;

   factory Photo.empty() => Photo(
         url: '',
         type: 'new',
         id: UniqueId(),
         name: PhotoName(''),
         description: PhotoDescription(''),
         tagList: TagList(new List()),
         watchCount: 0,
         author: '',
         serverTimeStamp: FieldValue.serverTimestamp(),
         uploadDate: DateTime.now().toString(),
       );

   Option<ValueFailure<dynamic>> get failureOption {
     return name.failureOrUnit
         .andThen(description.failureOrUnit)
         .andThen(tagList.failureOrUnit)
         .fold((f) => some(f), (r) => none());
   }
 }

【问题讨论】:

  • “因为 uploadDate 工作正常”是什么意思??什么时候不更新状态(在哪个产量)?
  • 我可以使用 uploadDate 更新照片实体,但生成用户的电子邮件和照片 url 不起作用。我打印了他们的值(print(state.photo.author)),但它是空的,并且 print(user.emailAddress.getOrCrash()) 可以工作并显示具体用户的电子邮件。所以我认为我正在产生空值,但我不知道它为什么会发生
  • 你能分享一下你的州课和照片课吗?
  • 没问题。已编辑。

标签: flutter dart firebase-storage bloc


【解决方案1】:

如果我没看错,您使用 .copyWith 会多次产生相同的状态。但是,为了更新 UI,您需要发送间歇状态。所以通常你会

yield myDisplayState(); yield inProgress(); yield myDisplayState(); yield inProgress(); yield myDisplayState();

如果您之间没有其他状态,您将在 UI 上看到没有变化

【讨论】:

  • 这是正确的,但是 copyWith 方法会创建一个新实例,这很好。
  • 意思是copyWith不需要中间状态?!很高兴知道
  • 是的,这意味着 copyWith 创建了您所谓的“中间状态”。如果 op 共享该类的代码,您将看到 copyWith 应该创建一个新实例,因此流将捕获更新。如果您将与以前完全相同的值传递给实例,则不会发生更新。
  • 我只是想实现这个。对于感兴趣的读者,首先需要将 .copyWith 实现为该特定状态的方法。见stackoverflow.com/a/63877434/13648205
  • @JoseGeorges 结果是:在我的情况下,它不会更新 UI,除非我在两者之间产生 InProgress 状态。我坚持我上次评论的例子。还有什么我可能错过的吗?在我的集团中,我已经为相关事件添加了MapToEventif (state is CustomerSearchDisplayResults) { CustomerSearchDisplayResults thisState = state as CustomerSearchDisplayResults;
猜你喜欢
  • 2020-07-28
  • 1970-01-01
  • 2020-04-28
  • 1970-01-01
  • 2021-05-10
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
相关资源
最近更新 更多