Tah*_*lam 6 flutter flutter-navigation flutter-bloc flutter-go-router
使用 flutter_bloc 和 go_router 实现基于身份验证更改的导航。
我需要做的是,如果用户经过身份验证,则应将其重定向到主屏幕,并能够导航身份验证流程...(HomeScreen,TestScreen1,TestScreen2)
如果用户在任何时候未经身份验证,则应将其重定向到登录屏幕,如果未知,则应重定向到启动屏幕。
我已经解决了许多 stackoverflow 问题和 github 问题,但没有一个提供我们如何实现这一目标的最佳实践。
问题:
提供以下资产:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<$T>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: $context
Run Code Online (Sandbox Code Playgroud)
======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for GoRouteInformationProvider:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
Run Code Online (Sandbox Code Playgroud)
改为context.read
而watch
不是我真正喜欢的,因为那样我就无法听取集团的变化。
到目前为止我尝试过的是:
我的应用程序路由器:
class AppRouter {
GoRouter get router => _goRouter;
late final GoRouter _goRouter = GoRouter(
routes: <GoRoute>[
GoRoute(
path: '/',
name: 'SPLASH',
builder: (context, state) => const SplashScreen(),
),
GoRoute(
path: '/auth',
name: 'AUTH',
builder: (context, state) => HomeScreen(),
routes: <GoRoute>[
GoRoute(
path: 'home_screen',
name: 'HOME',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: 'test_screen_1',
name: 'TEST_SCREEN_1',
builder: (context, state) => TESTSCREEN1(),
),
GoRoute(
path: 'test_screen_2',
name: 'TEST_SCREEN_2',
builder: (context, state) => TESTSCREEN2(),
),
],
),
GoRoute(
path: '/login_screen',
name: 'LOGIN',
builder: (context, state) => LoginScreen(),
),
],
redirect: (context, state) {
final authState = context.watch<AuthBloc>().state;
final loginLocation = state.namedLocation('LOGIN');
final authFlow = state.namedLocation('AUTH');
final splashLocation = state.namedLocation('SPLASH');
if (authState is AuthStateAuthenticated) {
return authFlow;
} else if (authState is AuthStateUnAuthenticated) {
return loginLocation;
} else {
return splashLocation;
}
},
);
}
Run Code Online (Sandbox Code Playgroud)
应用程序:
class App extends StatelessWidget {
AppRouter appRouter = AppRouter();
@override
Widget build(BuildContext context) {
return RepositoryProvider<AuthService>(
create: (context) => AuthService(),
child: MultiBlocProvider(
providers: [
BlocProvider<AuthBloc>(create: (context) => AuthBloc(authService: RepositoryProvider.of<AuthService>(context))),
],
child: MaterialApp.router(
routerDelegate: appRouter.router.routerDelegate,
routeInformationParser: appRouter.router.routeInformationParser,
routeInformationProvider: appRouter.router.routeInformationProvider,
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 flutter_bloc 和 get_it 进行依赖注入,并且也在这个主题上苦苦挣扎(主要是由于缺乏适当的文档)。
最终我的解决方案基于官方文档中的这个示例。
步骤 1:在 auth_bloc.dart 文件中添加 AuthStreamScope 和 AuthStream 类。
注意:在下面的代码中,替换getIt.get<AuthBloc>()
为您的 auth bloc 实例:
class AuthStreamScope extends InheritedNotifier<AuthStream> {
AuthStreamScope({super.key, required super.child}) : super(notifier: AuthStream(getIt.get<AuthBloc>().stream));
static AuthStream of(BuildContext ctx) => ctx.dependOnInheritedWidgetOfExactType<AuthStreamScope>()!.notifier!;
}
class AuthStream extends ChangeNotifier {
late final StreamSubscription<dynamic> _subscription;
AuthStream(Stream<dynamic> stream) {
notifyListeners();
_subscription = stream.asBroadcastStream().listen((_) => notifyListeners());
}
bool isSignedIn() => getIt.get<AuthBloc>().state.user != null;
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
第 2 步:使用 AuthStreamScope 包装您的应用程序:
// from with your app's build method:
return AuthStreamScope(
child: MaterialApp.router(
theme: theme,
darkTheme: darkTheme,
routerConfig: _routerInstance, // your GoRouter
),
),
);
Run Code Online (Sandbox Code Playgroud)
第三步:在你的GoRouter初始化中,监听auth的变化,如下所示。
GoRouter(
redirect: (BuildContext context, GoRouterState state) async {
// calling `of` method creates a dependency of AuthStreamScope. It will make go_router to reparse
// current route if AuthStream has new sign-in information.
final bool loggedIn = AuthStreamScope.of(context).isSignedIn();
// implement your redirection logic here
return null; // no need to redirect
},
// routes, etc.
)
Run Code Online (Sandbox Code Playgroud)
因此本质上 GoRouter 正在侦听任何 AuthBloc 流更新并相应地重定向。特别是 Auth,与其他块不同,可以定义为(惰性)单例,因此 GetIt 非常方便,如上面的代码所示。
我希望它有帮助。
归档时间: |
|
查看次数: |
3071 次 |
最近记录: |