繁体   English   中英

Flutter state go_router和riverpod管理错误

[英]Flutter state management error with go_router and riverpod

我实现了一个 Flutter 应用程序,我是一个真正的初学者。 我使用 Riverpod 进行 state 管理,使用 go_router 进行路由。 我尝试实现仅在您登录时才可见的导航栏。 但我认为我有一个 state 管理问题:当我按下导航栏按钮时,什么也没有发生(也没有控制台错误)但是如果我注销并登录或者如果我修改我的代码并保存,我的模拟器 go 到右侧页面。 我尝试将我的页面包装在一个更大的 Scaffold 中,以保持 AppBar 和 NavBar。 这是我的main.dart:

Future<void> main() async {

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widgets is the root of your application.
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = ref.watch(routerProvider);
    return MaterialApp.router(
      title: 'Ludocal 2',
      theme: ThemeData(
        primarySwatch: Colors.deepOrange,
      ),
      debugShowCheckedModeBanner: false,
      routeInformationProvider: router.routeInformationProvider,
      routeInformationParser: router.routeInformationParser,
      routerDelegate: router.routerDelegate,
    );
  }
}

我的路由器:

  List<GoRoute> get _routes => [
        GoRoute(
            name: 'login',
            builder: (context, state) => const LoginScreen(),
            path: '/login'),
        GoRoute(
            path: '/:screenName(home|game|event|profile)',
            builder: (BuildContext context, GoRouterState state) {
              final String screenName = state.params['screenName']!;
              return LoggedScreen(screenName: screenName);
            })
      ];

我的 logged_screen.dart 包装了我的其他屏幕:

class LoggedScreen extends HookConsumerWidget {
  const LoggedScreen({super.key, required this.screenName});

  final String screenName;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    Future.delayed(Duration.zero, () {
      switch (ref.read(indexProvider.state).state) {
        case 0:
          context.go('/home');
          break;
        case 1:
          context.go('/game');
          break;
        case 2:
          context.go('/event');
          break;
        case 3:
          context.go('/profile');
          break;
      }
    });
    return Scaffold(
      appBar: AppBar(
          title: Text("Ludocal 2"),
          backgroundColor: Colors.deepOrangeAccent,
          actions: [
            TextButton.icon(
              icon: Icon(
                Icons.logout_rounded,
                color: Colors.white,
              ),
              label: Text('', style: TextStyle(color: Colors.white)),
              onPressed: () async {
                ref.read(loginControllerProvider.notifier).signOut();
              },
            ),
          ]),
      body: BodyTab(screenName: screenName),
      bottomNavigationBar: const BottomTab(),
    );
  }
}

class BodyTab extends ConsumerWidget {
  const BodyTab({super.key, required this.screenName});

  final String screenName;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Column(
      children: [
        Expanded(
            child: screenName == 'home'
                ? const HomeScreen()
                : screenName == 'game'
                    ? const GameScreen()
                    : screenName == 'event'
                        ? const EventScreen()
                        : const ProfileScreen()),
      ],
    );
  }
}

class BottomTab extends ConsumerWidget {
  const BottomTab({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return BottomNavigationBar(
      currentIndex: ref.read(indexProvider.state).state,
      onTap: (int index) => ref.read(indexProvider.state).state = index,
      backgroundColor: Colors.deepOrangeAccent,
      items: const <BottomNavigationBarItem>[
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: 'Home',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.emoji_emotions),
          label: 'Game',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.calendar_today_rounded),
          label: 'Event',
        ),
      ],
    );
  }
}

final indexProvider = StateProvider<int>((ref) {
  return 0;
});

login_controller.dart:

class LoginController extends StateNotifier<LoginState> {
  LoginController(this.ref) : super(const LoginStateInitial());

  final Ref ref;

  void login(String email, String password) async {
    state = const LoginStateLoading();
    try {
      await ref.read(authRepositoryProvider).signInWithEmailAndPassword(
        email,
        password,
      );
      state = const LoginStateSuccess();
    } catch (e) {
      state = LoginStateError(e.toString());
    }
  }

  void signOut() async {
    await ref.read(authRepositoryProvider).signOut();
    state = const LoginStateInitial();
  }
}

final loginControllerProvider =
StateNotifierProvider<LoginController, LoginState>((ref) {
  return LoginController(ref);
});

感谢帮助。

对于导航,您需要使用如下所示的监听。

    ref.listen(indexProvider, (previous, next) {

      switch (next) {
        case 0:
          context.go('/home');
          break;
        case 1:
          context.go('/game');
          break;
        case 2:
          context.go('/event');
          break;
        case 3:
          context.go('/profile');
          break;
      }

    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM