firebase - 使用 copywith 时 Flutter Bloc 状态未更新

标签 firebase flutter google-cloud-firestore bloc

大纲:

  1. 导航到个人资料页面
  2. 传入用户 ID 以从 firestore 获取文档
  3. 将检索到的数据传递给 state.copyWith(data:data)
  4. 产生一个成功的状态并呈现用户界面

我的问题是,当我使用 state.copyWith(data:data) 时,即使数据 100% 存在,状态也没有更新,因为我可以在控制台中打印它。

代码:

UI: 
class ProfileView extends StatelessWidget {
  final String uid;

  final UserRepository userRepository = UserRepository();

  ProfileView({required this.uid});

  @override
  Widget build(BuildContext context) {
    // Init repository
    return BlocProvider<ProfileBloc>(
        create: (context) => ProfileBloc(
            // Should be able to pull user repo from context
            userRepository: UserRepository(),
            isCurrentUser: UserRepository().isCurrentUser(uid))
          ..add(InitializeProfile(uid: uid)),
        // Get User Doc
        child: _profileView(context));
  }

  Widget _profileView(context) {
    return BlocListener<ProfileBloc, ProfileState>(
      listener: (context, state) {
        if (state.imageSourceActionSheetIsVisible) {
          _showImageSourceActionSheet(context);
        }
        final loadingStatus = state.loadingStatus;
        if (loadingStatus is LoadingFailed) {
          showSnackBar(context, state.loadingStatus.exception.toString());
        }
        if (loadingStatus is LoadingInProgress) {
          LoadingView();
        }
        if (loadingStatus is LoadingFailed) {
          LoadingFailedView(exception: loadingStatus.exception.toString());
        }
      },
      child: Scaffold(
        appBar: _appBar(),
        body: _profilePage(),
        bottomNavigationBar: bottomNavbar(context),
      ),
    );
  }



BLoC:
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
  final bool isCurrentUser;
  final UserRepository userRepository;
  final _imagePicker = ImagePicker();

  ProfileBloc({
    required this.isCurrentUser,
    required this.userRepository,
  }) : super(ProfileState(
            isCurrentUser: isCurrentUser, loadingStatus: LoadingInProgress()));

  @override
  Stream<ProfileState> mapEventToState(
    ProfileEvent event,
  ) async* {
    if (event is InitializeProfile) {
      yield* _initProfile(uid: event.uid);
    }
  }

  Stream<ProfileState> _initProfile({required String uid}) async* {
    // Loading View
    yield state.copyWith(loadingStatus: LoadingInProgress());
    // Fetch profile data
    try {
      final snapshot = await userRepository.getUserDoc(uid);
      if (snapshot.exists) {
        final data = snapshot.data();
        print(data['fullName']);

        yield state.copyWith(
          fullName: data["fullName"].toString(),

        );
        print(state.fullName);
        yield state.copyWith(loadingStatus: LoadingSuccess());
      }
 
      else {
        yield state.copyWith(
            loadingStatus: LoadingFailed("Profile Data Not present :("));
      }
    } catch (e) {
      print(e);
    }
  }


State:
part of 'profile_bloc.dart';

class ProfileState {
  final bool isCurrentUser;
  final String? fullName;
  final LoadingStatus loadingStatus;
  bool imageSourceActionSheetIsVisible;

  ProfileState({
    required bool isCurrentUser,
    this.fullName,
    this.loadingStatus = const InitialLoadingStatus(),
    imageSourceActionSheetIsVisible = false,
  })  : this.isCurrentUser = isCurrentUser,
        this.imageSourceActionSheetIsVisible = imageSourceActionSheetIsVisible;

  ProfileState copyWith({
    bool? isCurrentUser,
    String? fullName,
    LoadingStatus? loadingStatus,
    bool? imageSourceActionSheetIsVisible,

  }) {
    print('State $fullName');
    print('State ${this.fullName}');
    return ProfileState(
      isCurrentUser: this.isCurrentUser,
      fullName: fullName ?? this.fullName,
      loadingStatus: loadingStatus ?? this.loadingStatus,
      imageSourceActionSheetIsVisible: imageSourceActionSheetIsVisible ??
          this.imageSourceActionSheetIsVisible,
    );
  }
}


新更新的代码实现 Bloc 构建器而不是建议的监听器

  Widget _profileView(context) {
    return BlocBuilder<ProfileBloc, ProfileState>(builder: (context, state) {
      final loadingStatus = state.loadingStatus;
      if (loadingStatus is LoadingInProgress) {
        return LoadingView();
      }
      if (loadingStatus is LoadingFailed) {
        return LoadingFailedView(exception: loadingStatus.exception.toString());
      }
      if (loadingStatus is LoadingSuccess) {
        return Scaffold(
          appBar: _appBar(),
          body: _profilePage(),
          bottomNavigationBar: bottomNavbar(context),
        );
      }
      return LoadingView();
    });
  }

这段代码仍然停留在加载屏幕上,当我打印出各种状态时,它被注册为一个事件,但是在使用 copy with 后状态打印出 null

感谢您的帮助

最佳答案

这是因为您需要添加一个运算符来比较您的 ProfileState 对象。实际上,您的事件映射器会生成 ProfileState 对象,但所有这些对象都被视为相等,因此 UI 不会更新。 一个好的做法是让你的 state 实现 Equatable,所以你只需要定义用来比较对象的 props。

关于firebase - 使用 copywith 时 Flutter Bloc 状态未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67490575/

相关文章:

Flutter:ClipRRect 与带有 BoxDecoration 的容器

arrays - 有没有办法批量读取firebase文档

java - 如何读取 firestore 子集合并将其传递给 FirestoreRecyclerOptions

ios - Firebase - 对象数组未返回正常计数值

angularjs - Firestore - 添加带有数组的对象

list - flutter 将项目添加到列表

python - Firestore Python 中的完成处理

dictionary - 不断向 map 添加数据

android - Firebase Analytics - CrashReport 中的 NPE

reactjs - React + Firebase - 删除映射组件内的 firebase 对象