我正在使用 Riverpod 作为状态管理来开发我的应用程序,并且我使用了
go_router
包进行路由管理,专门用于将用户重定向到刷新令牌更新失败的登录页面。
所以我想要的是我想在重定向方法中观看我的refreshTokenViewModel
,这样如果refreshTokenState
失败,我想将用户重定向到登录页面。
问题是没有通知重定向方法。我知道,当我再次尝试再次访问该页面时(状态现已更新),我被重定向到登录页面。 请参考此视频:视频链接
因此,当我第一次在未经授权的情况下尝试访问任何页面时,我得到:
======== Exception caught by foundation library ====================================================
The following GoException was thrown while dispatching notifications for GoRouteInformationProvider:
Location cannot be empty.
When the exception was thrown, this was the stack:
#0 canonicalUri (package:go_router/src/path_utils.dart:125:5)
#1 RouteConfiguration.findMatch (package:go_router/src/configuration.dart:296:31)
#2 _RouteMatchListDecoder.convert (package:go_router/src/match.dart:947:23)
#3 Codec.decode (dart:convert/codec.dart:30:34)
#4 GoRouteInformationParser.parseRouteInformationWithDependencies (package:go_router/src/parser.dart:71:32)
#5 _RouterState._processRouteInformation (package:flutter/src/widgets/router.dart:749:8)
#6 _RouterState._handleRouteInformationProviderNotification (package:flutter/src/widgets/router.dart:767:5)
#7 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:433:24)
但是当尝试再次访问它时,我被重定向了。
我整天在互联网上搜索此类异常,但一无所获。
我尝试过的:
路由器提供商:
final _key = GlobalKey<NavigatorState>();
final routerProvider = Provider<GoRouter>((ref) {
***//when using watch the app remain stuck on the splash page* **
final authState = ref.read(refreshTokenViewModelProvider);
return GoRouter(
navigatorKey: _key,
debugLogDiagnostics: true,
initialLocation: '/',
refreshListenable: authState, ***//with/without it nothing changed***
routes: [....],
errorBuilder: (context, state) =>
const Center(child: CircularProgressIndicator()),
redirect: (context, state) {
*//cannot watch provider here Cannot use ref functions after the dependency of a provider changed but before the provider rebuilt*
bool isRefreshTokenFailure = (authState.refreshTokenState == RefreshTokenState.failure);
if (isRefreshTokenFailure) {
return "/login";
} else {
return null;
}
},
);
});
主要小部件构建方法 不知道该用什么,都不起作用。
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
或:
routerConfig: ref.watch(routerProvider),
@override
Widget build(BuildContext outContext) {
ref.watch(themeRProvider);
return MaterialApp.router(
routerConfig: ref.watch(routerProvider),
// routeInformationParser: router.routeInformationParser,
// routeInformationProvider: router.routeInformationProvider,
// routerDelegate: router.routerDelegate,
themeMode: themeProvider.themeMode == ThemeModeOption.light
? ThemeMode.light
: themeProvider.themeMode == ThemeModeOption.dark
? ThemeMode.dark
: ThemeMode.system,
theme: lightTheme,
darkTheme: darkTheme,
// home: SplashPage(),
);
}
refreshTokenViewModelProvider 的片段:
enum RefreshTokenState { initial, loading, success, failure , networkFailure}
class RefreshTokenViewModel extends ChangeNotifier {
RefreshTokenState _refreshTokenViewModelState = RefreshTokenState.initial;
RefreshTokenState get refreshTokenState => _refreshTokenViewModelState;
setFailure(UserError error) {
_refreshTokenViewModelState = RefreshTokenState.failure;
notifyListeners();
}
Future<void> refreshToken() async {
var response = await refreshTokenRepository.refreshToken();
if (response is Failure) {
setFailure(UserError(response.errorMessage));
} else {
setSuccess();
}
}
}
您需要创建一个本地
ValueNotifier
,它将作为 refreshListenable
传递到路由器。使用 ref.listen
收听 refreshTokenViewModelProvider
并用它更新 ValueNotifier
。
final routerProvider = Provider<GoRouter>((ref) {
final authStateNotifier = ValueNotifier(RefreshTokenState.initial);
ref
..onDispose(authStateNotifier.dispose)
..listen(refreshTokenViewModelProvider, (_, value) {
authStateNotifier.value = value;
});
// ...
return GoRouter(
// ...
refreshListenable: authStateNotifier,
redirect: (_, state) {
final authState = ref.read(refreshTokenViewModelProvider);
// ...
},
请参阅完整示例此处。