Bloc: Bloc State is not changing

Created on 25 May 2019  ·  14Comments  ·  Source: felangel/bloc

Hi ,

I am new in BloC pattern and im getting an issue.I make login authenticate workflow. I make raised button and not changing if i add future delay but without future delay it's changing state.

  • Home Page
    _authenticationBloc = BlocProvider.of<AuthenticationBloc>(context);
        child: RaisedButton(
            onPressed: () =>
                _authenticationBloc.dispatch(LoggedOut())),
      ),
  • Login Page
  void initState() {
    _authenticationBloc = AuthenticationBloc();
    // print('Hello');
    _authenticationBloc.dispatch(AppStarted());
    super.initState();
  }

Widget build(BuildContext context) {
    return BlocProvider<AuthenticationBloc>(
      bloc: _authenticationBloc,
      child: Scaffold(
        body: BlocBuilder<AuthenticationEvent, AuthenticationState>(
          bloc: this._authenticationBloc,
          builder: (BuildContext context, AuthenticationState state) {
            print('root_page change');
            print(this._authenticationBloc.currentState);
            if (state is AuthenticationAuthenticated) {
              return Center(
                child: Text('AuthenticationAuthenticated'),
              );
            }
            if (state is AuthenticationUnauthenticated) {
              return HomePage();
            }
            if (state is AuthenticationLoading) {
              return Center(
                child: CircularProgressIndicator(),
              );
            }
            if (state is AuthenticationFailure) {
              return Center(
                child: Text('AuthenticationFailure'),
              );
            }
            return Container();
          },
        ),
      ),
    );

  • This is the BloC Class ;
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import 'Events/AuthenticateEvent.dart';
import 'States/AuthenticateState.dart';

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  @override
  AuthenticationState get initialState => AuthenticationUninitialized();

  @override
  Stream<AuthenticationState> mapEventToState(
      AuthenticationEvent event) async* {
    if (event is AppStarted) {
      bool hasToken = false;
      if (hasToken) {
        yield AuthenticationAuthenticated();
      } else {
        yield AuthenticationUnauthenticated();
      }
    }
    if (event is LoggedIn) {
      yield AuthenticationLoading();
      bool isSuccessLogin = true; //login repodan geldiğini varsayalım.
      await Future.delayed(const Duration(seconds: 2));
      if (isSuccessLogin) {
        print(this.currentState);
        yield AuthenticationAuthenticated();
      } else {
        print(this.currentState);
        yield AuthenticationFailure();
      }
    }

    if (event is LoggedOut) {
      print('Logout');
      print(this.currentState);
      yield AuthenticationLoading();
      print(this.currentState);
      await Future.delayed(const Duration(milliseconds: 300));

      if (true) {
        print('Inside the if');
        yield AuthenticationUnauthenticated();
        print(this.currentState);
      }
    }
  }
}
  • State
abstract class AuthenticationState {}

/// sayfanın ilk açılması anı. Sayfanın ilk açılma anı.
class AuthenticationUninitialized extends AuthenticationState {
  @override
  String toString() => 'AuthenticationUninitialized';
}

/// Kullanıcı yetkilendirmesi başarılı. Homepage görecek.
class AuthenticationAuthenticated extends AuthenticationState {
  @override
  String toString() => 'AuthenticationAuthenticated';
}

/// Kullanıcı yetkili değil. Login formunu görecek.
class AuthenticationUnauthenticated extends AuthenticationState {
  @override
  String toString() => 'AuthenticationUnauthenticated';
}

/// Sayfanın yüklenmesi bekleniyor. Loading Screen görecek.
class AuthenticationLoading extends AuthenticationState {
  @override
  String toString() => 'AuthenticationLoading';
}

/// Servis hata dönmesi durumu 404 500 vb veya şifre password yanlış dönmesi durumu.
class AuthenticationFailure extends AuthenticationState {
  @override
  String toString() => 'AuthenticationLoading';
}

  • Events
import 'package:meta/meta.dart';

abstract class AuthenticationEvent {
  AuthenticationEvent();
}

class AppStarted extends AuthenticationEvent {
  @override
  String toString() => 'AppStarted';
}

class LoggedIn extends AuthenticationEvent {
  final String token;

  LoggedIn({@required this.token});

  @override
  String toString() => 'LoggedIn { token: $token }';
}

class LoggedOut extends AuthenticationEvent {
  @override
  String toString() => 'LoggedOut';
}

question

Most helpful comment

@felangel thank you man , you're great !

All 14 comments

@mfarkan As per my knowledge bloc does not work this way. It internally uses inherited widget structure on flutter but you are initialising the bloc and using the builder in the same widget.

See this example: https://felangel.github.io/bloc/#/fluttercountertutorial

Try this once:

  • Initialise the bloc in a stateful widget and in its child method show your login page.
  • Now login page's parent widget will be a bloc builder and now your login page will update on state changes.

@ishaan1995 hmm , yes i create instance of bloc class inside i will check this but creating this item inside the initState and obviously its a statefulwidget ? the Point is i delete the delayed future state is change...

So confusing.

Thank you

Yes the state will change but the class actually initialising the bloc provider won't listen to changes. Maybe try the bloc listener.
I think bloc builder don't listen to changes in the class its initialised.

Maybe @felangel might give more context on this?

Hey @mfarkan 👋
Thanks for opening an issue!

Can you please share a link to a sample project with the problem you're having? It would be much easier for me to help if I can run the project locally and reproduce the issue. Thanks! 👍

Hi , @felangel thank you for reply here is the dummy application. I think i am missing something but cant find it :)

https://ufile.io/0i6dher9

Regards ,

@mfarkan I just took a look at it seems like everything is working as it should. I think the problem is in your code you are returning the HomePage when the state is Unauthenticated.

if (state is AuthenticationUnauthenticated) {
    return HomePage();
}

If you change it to return the LoginPage on AuthenticationUnauthenticated and return the HomePage on AuthenticationAuthenticated it should work as you expect.

Hope that helps 👍

Hi , @felangel i took your advise and change the code but its not changing. First it sent me to login page as expected after that click the login button and sent me to home page as expected after click the logout button.State is AuthenticationLoading not AuthenticationUnauthenticated.I dont get it.

Change code like this and getting this output ;

    if (event is LoggedOut) {
      print(this.currentState);
      yield AuthenticationLoading();
      print(this.currentState);
      await Future.delayed(const Duration(seconds: 2));
      print(this.currentState);
      if (true) {
        print('inside If');
        print(this.currentState);
        yield AuthenticationUnauthenticated();
        print(this.currentState);
      }
    }
I/flutter ( 4425): AuthenticationLoading
I/flutter ( 4425): AuthenticationLoading
I/flutter ( 4425): inside If
I/flutter ( 4425): AuthenticationLoading
I/flutter ( 4425): AuthenticationLoading

and here is the sample of project ;

https://ufile.io/3sjucjpx

@felangel any update for this ?

@mfarkan that's because you are disposing the AuthenticationBloc in the HomePage. You should not dispose it there because the AuthenticationBloc is still being used even after the HomePage is disposed.

If you remove

  @override
  void dispose() {
    this._authenticationBloc.dispose();
    super.dispose();
  }

from home_page.dart it will all work. In general, you should dispose the bloc in the widget where it was created.

I highly suggest you go through the login tutorial.

@felangel thank you man , you're great !

Hi @felangel

I'm currently having similar issues like I'm just trying to display the validation errors in the login form.
I have followed up your login tutorials the basic login and firebase login.

if I just use the basic form without validation, I get it working without any problem.

But when I try to use the validation following the Firebase login, it not working, I can see the state.update firing on the screen, to validate the form or to show the snackbar.

I have created below repo to reproduce, it would be much appreciated if you can help me out.

git clone https://github.com/jjoao07/Flutter-Login-App

Regards

Hi @jjoao07 I tried taking a look but I'm having trouble accessing the repo at the link you provided. Is it still publicly available?

Hi @felangel, yes is public
I also ended up publishing here on Github in the link below

https://github.com/jjoao07/Flutter-Login-App

so you can have look at that link.

Thanks

Hi @felangel ,

Don't worry about this.

I have ended up finding a workaround and everything is working fine now.

Was this page helpful?
0 / 5 - 0 ratings