I'm using go_router for navigation and flutter_bloc for my state management.
I would like to use refreshListenable and listen to my AuthBloC events in my GoRouter configuration, however, I don't have access to context in my GoRouter, and I would like not to provide it.
most of the answers I've found are outdated or use alternatives like StreamBuilder to re-render the whole app on event changes which are not ideal.
How can I listen to my AuthEvents outside of context?
main.dart
return RepositoryProvider.value(
value: authRepo,
child: BlocProvider(
create: (_) => AuthBloc(authRepo),
child: MaterialApp.router(
...
routerConfig: Routes.router,
builder: (_, child) {
final isRTL = LocaleSettings.currentLocale == AppLocale.ar;
return Directionality(
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
child: child!,
);
},
),
),
bloc/auth/auth_bloc.dart
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc(this._authenticationRepository) : super(const AuthState()) {
on<AuthEvent>((event, emit) {
event.when(
authStateChangeEvent: (account) => _authStateChangeEvent(account, emit),
signOutEvent: _signOutEvent,
verifyAccount: _verifyAccount,
);
});
_userSubscription = _authenticationRepository.user.listen((account) {
add(AuthEvent.authStateChangeEvent(account));
});
}
late final StreamSubscription<Account> _userSubscription;
final AuthenticationRepository _authenticationRepository;
void _authStateChangeEvent(
Account account,
Emitter<AuthState> emit,
) {
...
}
void _signOutEvent() {
...
}
void _verifyAccount() {
...
}
@override
Future<void> close() {
_userSubscription.cancel();
return super.close();
}
}
Router.dart
class Routes {
Routes._();
static final _rootNavigatorKey = GlobalKey<NavigatorState>();
static GoRouter get router => _router;
static final GoRouter _router = GoRouter(
navigatorKey: _rootNavigatorKey,
refreshListenable: , // ! Listen to Auth Changes
routes: [..._directNavigations, ..._nestedNavigations],
redirect: _authGuard, //
);
static String? _authGuard(BuildContext context, GoRouterState state) {
final authState = context.watch<AuthBloc>().state;
print(authState.toString());
final isAuthenticated = authState.authStatus == AuthStatus.authenticated;
final isVerified =
authState.account != null && authState.account!.emailVerified;
/// ... Some logic for redirection
return null;
}
...
}
I'm getting this error when I'm navigating with context.go/context.push
"Tried to listen to a value exposed with provider, from outside of the widget tree.\n\nThis is
js_primitives.dart:30 likely caused by an event handler (like a button's onPressed) that called\nProvider.of without
js_primitives.dart:30 passing `listen: false`.\n\nTo fix, write:\nProvider.of<AuthBloc>(context, listen: false);\n\nIt is
js_primitives.dart:30 unsupported because may pointlessly rebuild the widget associated to the\nevent handler, when the
js_primitives.dart:30 widget tree doesn't care about the value.\n\nThe context used was:
js_primitives.dart:30 Navigator-[LabeledGlobalKey<NavigatorState>#31496](dependencies: [HeroControllerScope,
js_primitives.dart:30 UnmanagedRestorationScope, _FocusTraversalGroupMarker], state: NavigatorState#795d6(tickers:
js_primitives.dart:30 tracking 1 ticker))\n"
full crashlog: https://pastebin.com/3A3pdKtr
Note: I'm willing to replace my Auth BloC with a change notifier but I'm not sure if it's the right way to deal with this problem.
redirect
andrefreshListenable
methods. This way, each GoRoute/ShellRoute can continue to be clean and easy to understand. In my case, I have GoRoutes outside ShellRoutes, because I need to do Onboarding. – Internuncio