firebase - Flutter FirebaseAuth authStateChanges Not Navigating in initState - Stack Overflow

I'm using Firebase Authentication in my Flutter app to detect user authentication state changes an

I'm using Firebase Authentication in my Flutter app to detect user authentication state changes and navigate accordingly. However, the navigation inside initState does not work.

./main.dart:

import 'package:app/authentication/email_auth.dart';
import 'package:app/authentication/landing.dart';
import 'package:app/authentication/signup.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'authentication/login.dart';
import 'package:google_fonts/google_fonts.dart';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  User? _user;

  @override
  void initState() {
    super.initState();
    FirebaseAuth.instance.authStateChanges().listen((user) {
      print("User state changed: ${user?.uid}");
      FocusManager.instance.primaryFocus?.unfocus();

      setState(() {
        _user = user;
      });

      if (user != null) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          Navigator.pushAndRemoveUntil(
            context,
            MaterialPageRoute(builder: (context) => HomeScreen()),
            (route) => false,
          );
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarIconBrightness: ThemeMode.system == ThemeMode.light
            ? Brightness.dark
            : Brightness.light));
    return MaterialApp(
      // app data
      title: 'MyApp',

      // app navigation
      routes: {
        Login.routeName: (context) => const Login(),
        Signup.routeName: (context) => const Signup(),
        EmailAuth.routeName: (context) => const EmailAuth(),
        Landing.routeName: (context) => const Landing(),
        HomeScreen.routeName: (context) => HomeScreen(),
      },

      home: Landing(),

      themeMode: ThemeMode.dark,
      theme: ThemeData(scaffoldBackgroundColor: Color(0xff222531)),
      darkTheme: ThemeData(
        scaffoldBackgroundColor: Color(0xff222531),
        bottomAppBarTheme: BottomAppBarTheme(color: Colors.red),
        useMaterial3: true,
        textTheme: TextTheme(
            labelMedium: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
            labelSmall: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13),
            bodyLarge: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w500, fontSize: 24),
            headlineSmall: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w400, fontSize: 22),
            displayMedium: GoogleFonts.montserrat(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 40),
            headlineLarge: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w400)),
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  HomeScreen({
    super.key,
  });
  static const routeName = "/home";
  final user = FirebaseAuth.instance.currentUser;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () async {
          print("pressed");
          await FirebaseAuth.instance.signOut();
        },
        child: Center(
          child: Text(
            user?.email ?? "hello",
            style: Theme.of(context).textTheme.headlineLarge,
          ),
        ),
      ),
    );
  }
}

Issue:

  • The authentication state change is detected (confirmed by print() logs).
  • However, Navigator.pushAndRemoveUntil does not work, and the screen does not change.

How can I fix this issue and ensure the navigation happens when the user logs in?

Things I Have Tried:

  • Wrapping Navigator.pushAndRemoveUntil inside WidgetsBinding.instance.addPostFrameCallback
  • Checking if mounted before calling Navigator
  • Adding a small delay with Future.delayed(Duration(milliseconds: 100), () {...})
  • Moving navigation logic to build() instead of initState
  • Ensuring MaterialPageRoute is correctly defined
  • None of these solutions have worked.

I was expecting the sign-in to go ahead and the user be navigated to the homePage() page. But in reality the sign in is successful while the navigation is not!

I'm using Firebase Authentication in my Flutter app to detect user authentication state changes and navigate accordingly. However, the navigation inside initState does not work.

./main.dart:

import 'package:app/authentication/email_auth.dart';
import 'package:app/authentication/landing.dart';
import 'package:app/authentication/signup.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'authentication/login.dart';
import 'package:google_fonts/google_fonts.dart';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  User? _user;

  @override
  void initState() {
    super.initState();
    FirebaseAuth.instance.authStateChanges().listen((user) {
      print("User state changed: ${user?.uid}");
      FocusManager.instance.primaryFocus?.unfocus();

      setState(() {
        _user = user;
      });

      if (user != null) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          Navigator.pushAndRemoveUntil(
            context,
            MaterialPageRoute(builder: (context) => HomeScreen()),
            (route) => false,
          );
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarIconBrightness: ThemeMode.system == ThemeMode.light
            ? Brightness.dark
            : Brightness.light));
    return MaterialApp(
      // app data
      title: 'MyApp',

      // app navigation
      routes: {
        Login.routeName: (context) => const Login(),
        Signup.routeName: (context) => const Signup(),
        EmailAuth.routeName: (context) => const EmailAuth(),
        Landing.routeName: (context) => const Landing(),
        HomeScreen.routeName: (context) => HomeScreen(),
      },

      home: Landing(),

      themeMode: ThemeMode.dark,
      theme: ThemeData(scaffoldBackgroundColor: Color(0xff222531)),
      darkTheme: ThemeData(
        scaffoldBackgroundColor: Color(0xff222531),
        bottomAppBarTheme: BottomAppBarTheme(color: Colors.red),
        useMaterial3: true,
        textTheme: TextTheme(
            labelMedium: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
            labelSmall: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13),
            bodyLarge: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w500, fontSize: 24),
            headlineSmall: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w400, fontSize: 22),
            displayMedium: GoogleFonts.montserrat(
                color: Colors.white, fontWeight: FontWeight.bold, fontSize: 40),
            headlineLarge: GoogleFonts.inter(
                color: Colors.white, fontWeight: FontWeight.w400)),
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  HomeScreen({
    super.key,
  });
  static const routeName = "/home";
  final user = FirebaseAuth.instance.currentUser;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () async {
          print("pressed");
          await FirebaseAuth.instance.signOut();
        },
        child: Center(
          child: Text(
            user?.email ?? "hello",
            style: Theme.of(context).textTheme.headlineLarge,
          ),
        ),
      ),
    );
  }
}

Issue:

  • The authentication state change is detected (confirmed by print() logs).
  • However, Navigator.pushAndRemoveUntil does not work, and the screen does not change.

How can I fix this issue and ensure the navigation happens when the user logs in?

Things I Have Tried:

  • Wrapping Navigator.pushAndRemoveUntil inside WidgetsBinding.instance.addPostFrameCallback
  • Checking if mounted before calling Navigator
  • Adding a small delay with Future.delayed(Duration(milliseconds: 100), () {...})
  • Moving navigation logic to build() instead of initState
  • Ensuring MaterialPageRoute is correctly defined
  • None of these solutions have worked.

I was expecting the sign-in to go ahead and the user be navigated to the homePage() page. But in reality the sign in is successful while the navigation is not!

Share Improve this question edited Jan 31 at 11:03 squarewatermeln asked Jan 31 at 10:12 squarewatermelnsquarewatermeln 33 bronze badges 1
  • Did/could you try stackoverflow/questions/66532753/… and or stackoverflow/q/51965326/209103? – Frank van Puffelen Commented Jan 31 at 16:19
Add a comment  | 

1 Answer 1

Reset to default 0

Ok so here's how i fixed it:

i moved to contextless navigation, so i defined a GlobalKey<NavigatorState> globally in main.dart:

./main.dart:

// global navigation
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

then inside initState() (main.dart):

FirebaseAuth.instance.authStateChanges().listen((user) {
  FocusManager.instance.primaryFocus?.unfocus();

  setState(() {
    _user = user;
  });

  if (user != null) {
    navigatorKey.currentState?.pushNamed("/home");
  }
});

and in MaterialApp() (main.dart) you have to add this line:

navigatorKey: navigatorKey,

however i am yet to investigate the potential drawbacks with this approach (when i find them i will list them down below)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745269743a4619670.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信