flutter Bloc + Freezed 不会两次发出相同的状态。 UI 未重建

问题描述 投票:0回答:1

我试图在创建对象后更新状态。 我已经使用

freezed
包创建了 ObjectsState,因此没有必要使用 Equatable,因为它已经由包添加了。

class ObjectsState with _$ObjectsState {
  const factory ObjectsState.initial() = Initial;
  const factory ObjectsState.loading() = _Loading;
  const factory ObjectsState.loaded(ObjectsListResponse response) = Loaded;
  const factory ObjectsState.error(String message) = _Error;
}

那么,这是我的获取对象事件

@freezed
class ObjectsEvent with _$ObjectsEvent {
  const factory ObjectsEvent.onFetchObjects() = _OnFetchObjects;
}

但我也有单独的

CreateObjectEvent
。 还有我的块文件:

class ObjectsBloc extends Bloc<ObjectsEvent, ObjectsState> {
  final ObjectsUseCase objectsUseCase;

  ObjectsBloc({required this.objectsUseCase})
      : super(const ObjectsState.initial()) {
    on<ObjectsEvent>((event, emit) => event.when(
          onFetchObjects: () => _fetchObjects(emit),
        ));
  }

  Future<void> _fetchObjects(Emitter<ObjectsState> emit) async {
    emit(const ObjectsState.loading());

    try {
      final response = await objectsUseCase.executeFetchObjects();
      if (response.isError || response.result == null) {
        emit(ObjectsState.error(
            response.errorMessage ?? 'Failed to fetch objects'));
      } else {
        final updatedResponse = response.result!.copyWith(
          objectsList: List.from(response.result!.objectsList),
          total: response.result!.total,
        );

        final loadedState = ObjectsState.loaded(updatedResponse);
        final updatedState = (loadedState as Loaded).copyWith(
          response: updatedResponse,
        );
        emit(updatedState);
      }
    } catch (e) {
      emit(ObjectsState.error(e.toString()));
    }
  }
}

所以,在舞台上

emit(updatedState);
updatedState 具有正确的值,但是当它进入 UI 部分时 - 没有任何更新

class ObjectsScreenWrapper extends StatefulWidget {
  ObjectsScreenWrapper({super.key});

  @override
  State<ObjectsScreenWrapper> createState() => _ObjectsScreenWrapperState();
}

class _ObjectsScreenWrapperState extends State<ObjectsScreenWrapper> {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<ObjectsBloc>(
          create: (_) =>
              ObjectsBloc(
                objectsUseCase: GetIt.I<ObjectsUseCase>(),
              ),
        ),
        BlocProvider<BalanceBloc>(
          create: (_) =>
              BalanceBloc(
                balanceUseCase: GetIt.I<BalanceUseCase>(),
              ),
        ),
      ],
      child: ObjectsScreen(),
    );
  }
}

class ObjectsScreen extends StatelessWidget {
  ObjectsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    if (context.read<ObjectsBloc>().state is Initial) {
      context.read<ObjectsBloc>().add(const ObjectsEvent.onFetchObjects());
    }
     BlocBuilder<ObjectsBloc, ObjectsState>(
                key: ValueKey(context.watch<ObjectsBloc>().state),                   
                builder: (context, state) {
                    return state.when(
                           initial: ...
                           loading: ...
                           loaded: (objectsListResponse) {
                                if (objectsListResponse.total <= 0) {
                                  return ... ;
                                } else {
                                  return ObjectsLayoutGrid(
                                    key: ValueKey(objectsListResponse
                                        .copyWith()
                                        .objectsList
                                        .hashCode),

我发现了很多相关问题,但没有任何对我有用。如果有人知道如何解决这个问题,请帮忙

flutter dart state bloc freezed
1个回答
0
投票

据我所知,当我们与 Freezed 发出相同的状态时,UI 不会重建,因为 Freezed 会比较状态并在它们相等时跳过重建,因此为了确保 UI 重建,您可以添加一个更改的字段每个发出的时间戳如下:

修改您的状态

将 DateTime 或 int 像下面的字段添加到您的状态:

const factory ObjectsState.loaded(
  ObjectsListResponse response,
  {required DateTime updatedAt}
) = Loaded;

发出更新状态

发出新状态时,请包含更新的时间戳:

emit(ObjectsState.loaded(
  updatedResponse,
  updatedAt: DateTime.now(),
));
© www.soinside.com 2019 - 2024. All rights reserved.