Bloc: Dynamic initialState and yielding different instances of the same state with different props

Created on 9 Nov 2019  路  4Comments  路  Source: felangel/bloc

I'm actually facing 2 issues:
1) When I create a bloc, I have initial state with empty settings, but at the time the bloc is actually used, I already have the settings initialized, I would like to have dynamic initial state, so by the time a widget subscribes to the bloc, it receives the updated initialState, not the one, used when the bloc was created.

2) When I update settings, I need to yield the same state with different props, but the BlocBuilder won't rebuild, even if condition always returns true.

Here's some code:

import 'dart:async';

import 'package:aurora_mail/modules/settings/blocs/sync_settings/sync_settings_methods.dart';
import 'package:aurora_mail/modules/settings/models/sync_duration.dart';
import 'package:bloc/bloc.dart';

import './bloc.dart';

class SyncSettingsBloc extends Bloc<SyncSettingsEvent, SyncSettingsState> {
  SyncFreq syncDuration;

  final _methods = new SyncSettingsMethods();

  SyncSettingsState _currentState = InitialSyncSettingsState(300);

  @override
  SyncSettingsState get initialState => _currentState;

  @override
  Stream<SyncSettingsState> mapEventToState(
    SyncSettingsEvent event,
  ) async* {
    if (event is InitSyncSettings) yield* _initSyncSettings(event);
    if (event is SetFrequency) yield* _setFrequency(event);
  }

  Stream<SyncSettingsState> _initSyncSettings(InitSyncSettings event) async* {
    _currentState = InitialSyncSettingsState(event.user.syncFreqInSeconds);
    print("VO: freqInSeconds: ${event.user.syncFreqInSeconds}");
    yield InitialSyncSettingsState(event.user.syncFreqInSeconds);
  }

  Stream<SyncSettingsState> _setFrequency(SetFrequency event) async* {
    _methods.setFrequency(event.freq);
    final freqInSeconds = SyncFreq.freqToDuration(event.freq).inSeconds;
    print("VO: freqInSeconds: ${freqInSeconds}");

    _currentState = InitialSyncSettingsState(freqInSeconds);
    yield InitialSyncSettingsState(freqInSeconds);
  }
}

question

Most helpful comment

@felangel sorry, my mistake, I missed one param in the props getter so it caused both of the issues, my mistake. Thanks for the info though, it was very useful, and sorry for disturbing, the issues are closed

All 4 comments

Hi @VadimOsovsky 馃憢
Thanks for opening an issue!

  1. If the process of initializing the settings is asynchronous then you must start with some initial state and then load the settings via an event and update the state accordingly. You can make this process happen earlier rather than later so a user doesn鈥檛 have to wait by moving the bloc up in the widget tree and adding the initialization event as soon as possible.

  2. If you鈥檙e using Equatable you must pass all props to the equatable class. Please make sure you understand Equatable before using it because it鈥檚 an optimization which is not always necessary and can lead to undesired behavior when not implemented correctly. Please provide your state class implementation if you are still having trouble.

Hope that helps 馃憤

Edit: On a side note you don鈥檛 need to keep track of the blocs current state manually. You can get the blocs current state at any point in time using the state property.

Can I make it work like a Behaviour Subject, so when a new bloc builder/listener subscribes to it, it gets the latest value?

@VadimOsovsky that's how it currently works. Once a new BlocBuilder is created it will automatically get the latest bloc state. BlocListener only reacts to state changes so it will get updates on every state change. You can also access the latest bloc state via the state property

BlocProvider.of<MyBloc>(context).state; // latest state

Please refer to the documentation for more details.

@felangel sorry, my mistake, I missed one param in the props getter so it caused both of the issues, my mistake. Thanks for the info though, it was very useful, and sorry for disturbing, the issues are closed

Was this page helpful?
0 / 5 - 0 ratings