How to emit state from a stream?

495 Views Asked by At

Im learning flutter bloc. im trying to make a authentication event work.

This is my bloc

class SplashBloc extends Bloc<SplashEvent, SplashState> {
  final supabaseClient = Supabase.instance.client;
  StreamSubscription<AuthState>? _subscription;
  Session? userSession;
  SplashBloc() : super(SplashInitialState()) {
    on<SplashInitialEvent>(
      (event, emit) {
        // listenAuthState(event, emit);
      },
    );
  }
  @override
  Stream<SplashState> mapEventToState(SplashEvent event,) async* {
    _subscription?.cancel();
    if (event is SplashInitialEvent) {
            _subscription = supabaseClient.auth.onAuthStateChange.listen((event) {
        if (event.session?.accessToken != null) {
          emit(SignedInState()); // The member 'emit' can only be used within 'package:bloc/src/bloc.dart' or a test.
        } else {
          yield NotSignedInState(); //Yield statements must be in a generator function (one marked with either 'async*' or 'sync*').Try adding 'async*' or 'sync*' to the enclosing function.
        }
      });
    }
   }

What is the correct way to listen to a stream and update the state? I'm still figuring bloc any help would be appreciated.

1

There are 1 best solutions below

0
On

mapEventToState was removed from flutter_bloc years ago. I'm pretty sure you're seeing a warning about invalid override or something. Its definitely the reason you're seeing those other errors.

If you're in line with the up to date version of flutter bloc, then you usually don't have to manually create StreamSubscriptions. You can utilize emit.forEach.

There's some good reading about this here

This should be a mostly or fully working example based on what you provided.


class SplashInitListener extends SplashEvent {} // fire this whenever you want to init the listener, probably on app start

class SplashBloc extends Bloc<SplashEvent, SplashState> {
  final supabaseClient = Supabase.instance.client;
  // StreamSubscription<AuthState>? _subscription; // don't need this
  Session? userSession; // not sure you need this either, definitely not for the example below 
  SplashBloc() : super(SplashInitialState()) {
    on<SplashInitListener>(_onSplashInitListener);
  }

  Future<void> _onSplashInitListener(
    SplashInitListener event,
    Emitter<SplashState> emit,
  ) async {
    // emit.forEach takes a stream and returns a new state when the stream
    // is updated
    emit.forEach<AuthState>(
      supabaseClient.auth.onAuthStateChange, // stream from Supabase
      // The state returned from the onData callback is what is emitted and all listeners will be notified
      onData: (AuthState authState) {
        if (authState.session?.accessToken != null) {
          return SignedInState();
        } else {
          return NotSignedInState();
        }
      },
    );
  }
}

That should do it for 'ya