Wiktoor
Wiktoor

Reputation: 176

Widgets don't rebuild using go_router and async redirect

I've been trying to implement navigation from login page to home page based on authentication status from firebase. Untill now Ive had this simply done with bloc listener (therefore I know the whole auth thing works).

Flutter docs recomend using go_router for navigation so I want to use it, and following this docs I was able to achieve this- up to a point: https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/async_redirection.dart

Problem: upon new events in the authentication stream, go_router redirect is not called (and widgets are not rebuild), even if ChangeNotifier trigger notifyListeners.

In this whole picture I distinguish four components:

Do you have any hints on what am I doing wrong or missing here?

I know there are two thing I do differently from docs example:

I've read this question, but there are alternative solutions to my problem there, and before I try this I'd like to at least understand if this docs approach is doable : Reactive redirection using go_router and flutter_bloc with Auth and UnAuth Flow

ROUTER :

GoRouter(
      redirect: (context, state) async {
        // This part is different from docs example, as I use the firebase client directly here, not the AuthNotifier from context
        final currentUser =
            await RepositoryProvider.of<auth_repo.FirebaseAuthenticator>(
                    context,
                    listen: false)
                .currentUserStream()
                .first;

        // CORRECT USER IS RECEIVED HERE
        bool? isSignedIn = await currentUser?.isSignedIn();
        final bool loggingIn = state.matchedLocation == '/login';

        if (loggingIn || isSignedIn == null || isSignedIn == false) {
          return '/login';
        }

        if (isSignedIn) {
          return '/home';
        }

        return null;
      },
      routes: <RouteBase>[
        GoRoute(
          path: '/home',
          builder: (BuildContext context, GoRouterState state) {
            return const HomePage();
          },
          routes: <RouteBase>[
            GoRoute(
              path: 'account',
              builder: (BuildContext context, GoRouterState state) {
                return AccountPage();
              },
            ),
          ],
        ),
        GoRoute(
          path: '/login',
          builder: (BuildContext context, GoRouterState state) {
            return const LoginPage();
          },
        ),
      ],
    );

AuthChangeNotifier

class AuthChangeNotifier extends ChangeNotifier {
  Stream<auth_repo.User> userStream;
  AuthChangeNotifier(this.userStream) {
    userStream.asBroadcastStream().listen((_) {
      notifyListeners(); // THIS GETS CALLED
    });
  }
}

AuthNotifier

class AuthNotifier extends InheritedNotifier<AuthChangeNotifier> {
  AuthNotifier({
    Key? key,
    required auth_repo.AuthenticatorInterface authenticator,
    required Widget child,
  }) : super(
          key: key,
          notifier: AuthChangeNotifier(authenticator.currentUserStream()),
          child: child,
        );

  static Stream<auth_repo.User> of(BuildContext context) {
    final AuthChangeNotifier? result =
        context.dependOnInheritedWidgetOfExactType<AuthNotifier>()!.notifier;
    if (result == null) {
      throw FlutterError(
          'AuthNotifier.of() called with a context that does not contain an AuthNotifier.');
    }
    return result.userStream;
  }
}

Use of AuthNotifier

    // This part is different from docs, as before I use AuthNotifier, I instantiate all blocs and providers
    return _blocProvider(
      _repositoryProvider(
        AuthNotifier(authenticator: _authenticator, child: const MyApp()),
      ),
    );

Upvotes: 0

Views: 41

Answers (0)

Related Questions