rodydavis / signals.dart

Reactive programming made simple for Dart and Flutter
http://dartsignals.dev
Apache License 2.0
378 stars 44 forks source link

Question : Go Router with Signals. #270

Closed iSaqibShafique closed 3 weeks ago

iSaqibShafique commented 3 weeks ago

I want to ask about an issue I encountered while using GoRouter with signals. When the user logs out, the application doesn't remove the route and gives a "Location cannot be empty" error. I reported this, and the Flutter team mentioned it might be a state management-related error. Is this correct?

rodydavis commented 3 weeks ago

Can you share a sample code snippet to reproduce?

rodydavis commented 3 weeks ago

Here is an example of signals a go_router working:

https://github.com/rodydavis/signals.dart/blob/main/examples/auth_flow/lib/main.dart

iSaqibShafique commented 3 weeks ago

Here's the code

class AppRoutes {
  static String splash = "/";
  static String login = "/login";
  static String register = "/register";
  static String maindashboardview = "/maindashboardview";
  static String forgotpassword = "/forgotpassword";
  static String emailnotverified = "/emailnotverified";
  static GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
  static GoRouter router = GoRouter(
    routes: [
      GoRoute(
        path: splash,
        name: splash,
        builder: (context, state) => const LoadingScreenView(),
        redirect: (context, state) {
         FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
          if (user != null && user.emailVerified) {
            return maindashboardview;
          } else if (user != null && user.emailVerified == false) {
            return emailnotverified;
          } else {
            return login;
          }
        },
      ),
      GoRoute(
        path: login,
        name: login,
        builder: (context, state) => const LoginView(),
      ),
      GoRoute(
        path: register,
        name: register,
        builder: (context, state) => const RegisterView(),
      ),
      GoRoute(
        path: maindashboardview,
        name: maindashboardview,
        builder: (context, state) => const DashboardView(),
      ),
      GoRoute(
        path: forgotpassword,
        name: forgotpassword,
        builder: (context, state) => const ForgotPasswordView(),
      ),
      GoRoute(
        path: emailnotverified,
        name: emailnotverified,
        builder: (context, state) => const EmailNotVerifiedScreen(),
      ),
    ],
    refreshListenable: FirebaseAuthService().currentUser.toValueListenable(),
    debugLogDiagnostics: true,
    initialLocation: "/",
    navigatorKey: key,
  );
}

//! Refresh Listener.

StreamSignal<User?> currentUser = StreamSignal(
    () {
      final FirebaseAuth auth = FirebaseAuth.instance;
      return auth.authStateChanges().map((event) {
        return event;
      });
    },
  );
iSaqibShafique commented 3 weeks ago

The problem I was facing when the user "Logut", goRouter gives an error "Location can't be empty"

rodydavis commented 3 weeks ago

But that error would be in go_router right?

To make sure it is working correctly, swap out the currentUser signal with a manual one for testing and add some tests to make sure the guards are correctly called.

I also would use the connect method here instead of an async stream signal.

final currentUser = signal<User?>(null);
...
connect(currentUser) << FirebaseAuth.instance.authStateChanges();
...
final _router = GoRouter(
  ...
  refreshListenable: currentUser.toValueListenable(),
);
iSaqibShafique commented 3 weeks ago

Thank you for your response. I explored the "GoRouter" package and found an error there, but the signals are working perfectly.