Search code examples
flutterbloccubitflutter-cubit

BlocListener does not listen for emitted state from cubit


I am facing some issue with emiting state from done action. I would like to make following flow:

  1. Click login button;
  2. Go through login process;
  3. After successful login, navigate to some page;

The problem is that code inside listener of BlocListener is never reached, even if state is valid (in LoginCubit I made after emitting LoginState.success() some check if state == LoginState.success() which returned true;)

I am also using freezed library to generate states. My question is- have I missed something with my implementation?

This is my cubit:

class LoginCubit extends CubitBase<LoginState>{
  LoginCubit() : super(const LoginState.created());

  Future<void> runLoginFlow() async {
    final isAuthorized = await startAuth();

    if(isAuthorized){
      emit(const LoginState.success());
    }
    emit(const LoginState.failed(failedLogin));
  }

  Future<bool> startAuth() async {
    //doing some stuff
  }
} 

State (generated with freezed):

@freezed
class LoginState with _$LoginState{
  const factory LoginState.created() = _Created;
  const factory LoginState.failed(String message) = _Failed;
  const factory LoginState.success() = _Success;
}

And my UI:

@RoutePage()
class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<LoginCubit>(
      create: (context) => LoginCubit(),
      child: Scaffold(
        body: BlocListener<LoginCubit, LoginState>(
          listener: (context, state) {
            if(state == LoginState.success()){
              AutoRouter.of(context).navigate(NextPageRoute())
            }
          },
          bloc: LoginCubit(),
          child: _buildContent(context),
      ),
    ),
    );  
  }
}

Thanks in advance for every helpful advice!


Solution

  • Only specify the bloc if you wish to provide a bloc that is otherwise not accessible via BlocProvider and the current BuildContext. remove bloc: LoginCubit() field in your bloc listener since you're providing it above.

    return BlocProvider<LoginCubit>(
          create: (context) => LoginCubit(),
          child: Scaffold(
            body: BlocListener<LoginCubit, LoginState>(
              listener: (context, state) {
                if(state == LoginState.success()){
                  AutoRouter.of(context).navigate(NextPageRoute())
                }
              },
              bloc: LoginCubit(),// Remove this
              child: _buildContent(context),
          ),
        ),
        );