BlocBuilder not updating after cubit emit
Asked Answered
C

2

18

UPDATE After finding the onChange override method it appears that the updated state is not being emitted #confused

UPDATE 2 Further debugging revealed that the StreamController appears to be closed when the updated state attempts to emit.

For some reason 1 of my BlocBuilders in my app refuses to redraw after a Cubit emit and for the life of me I cannot figure out why, there are no errors when running or debugging, the state data is being updated and passed into the emit.

Currently, it is a hook widget, but I have tried making it Stateless, Stateful, calling the cubit method in an effect, on context.bloc.

I have tried making it a consumer, nothing makes it into the listen, even tried messing with listenWhen and buildWhen and nothing is giving any indication as to why this is not building.

It renders the loading state and that is where it ends.

Widget:

class LandingView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final hasError = useState<bool>(false);

    return Scaffold(
      key: const Key(LANDING_VIEW_KEY),
      body: BlocProvider<CoreCubit>(
        create: (_) => sl<CoreCubit>()..fetchDomainOptions(),
        child: BlocBuilder<CoreCubit, CoreState>(
          builder: (context, state) {
            switch (state.status) {
              case CoreStatus.loaded:
                return LandingViewLoaded();
              case CoreStatus.error:
                return LandingViewError();
              case CoreStatus.loading:
              default:
                return AppIcon();
            }
          },
        ),
      ),
    );
  }
}

Cubit method:

  Future<void> fetchDomainOptions() async {
    final inputEither = await getDomainOptions();

    return inputEither.fold(
      _handleFailure,
      (options) {
        emit(state.copyWith(
          domainOptions: options,
          status: CoreStatus.loaded,
        ));
      },
    );
  }

I have a few other widgets that work off freezed data classes and work of the same status key logic without any issues, I even went as far as trying to add a lastUpdated timestamp key onto it to make even more data change, but in the initial state domainOptions is null and status is CoreStatus.loading, which should already be enough to trigger a UI update.

TIA

Counterpressure answered 15/10, 2020 at 11:51 Comment(5)
Did you solve this problem? For me, Even if I am emitting the state, it is still having the old state. For me, I am re-fetching a list. For the first time, it works fine but when I re-fetch the list, I emit a loading state, but after emitting the loading state, I see loaded state (from last fetch)Pelligrini
@Pelligrini Try to convert to the stateful widgetDedication
@ZEHINZ for me, I was overriding equality operator for state and the state that I was emiting was making it same as old state.Pelligrini
hi,did you solve this problem?i have this problem,in second page cannot update firstpage,but i get new data from server but do not update pageFleetwood
Any update on this? Same hereGagman
S
11

I haven't figured out yet why exactly this happens but I believe we're dealing with some kind of race condition here. Also, I don't know the proper solution to work around that but I have found that delaying calling emit() for a short amount of time prevents this issue from occurring.

void load() async {
  try {
    emit(LoadingState());
    final vats = await provider.all();
    await Future<void>.delayed(const Duration(milliseconds: 50));
    emit(LoadedState(vats));
  } catch (e) {
    print(e.toString());
    emit(ErrorState());
  }
}

Add await Future<void>.delayed(const Duration(milliseconds: [whatever is needed])); before emitting your new state.

I came to this conclusion after reading about this issue on cubit's GitHub: Emitted state not received by CubitBuilder

Shawnee answered 15/10, 2020 at 20:55 Comment(2)
Thanks, that, however, did not solve the problem, but lead me to the onChange override which indicates that the state is in fact not emitting. That's going to be a fun one to work out why.Counterpressure
This solved it for me too. So, so dodgy to need to hard code a delay to make the emit work - I am super disappointed by BLoc ... will go with this for now I guess though.Larghetto
H
-2

I resolved my problem, I was using getIt. I added the parameter bloc. My problem was not receiving the events (emit) of the cubit (bloc)

child: BlocBuilder<CoreCubit, CoreState>(
  bloc: getIt<CoreCubit>(), // <- this
  builder: (context, state) {},
),
Heddi answered 15/3, 2022 at 2:2 Comment(1)
Combine GetIt with Bloc seem not best solution but It can work.Blaze

© 2022 - 2024 — McMap. All rights reserved.