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.
_authenticationBloc = BlocProvider.of<AuthenticationBloc>(context);
child: RaisedButton(
onPressed: () =>
_authenticationBloc.dispatch(LoggedOut())),
),
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();
},
),
),
);
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);
}
}
}
}
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';
}
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';
}
@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:
@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 :)
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 ;
@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.
Most helpful comment
@felangel thank you man , you're great !