You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Riverpod监听结合NavigatorState导航时currentState为null如何解决

问题根因
  • 你把导航逻辑写在了MaterialApp的builder回调里同步执行,这个回调属于组件同步构建阶段,此时Navigator还没完成和_navigatorKey的绑定,currentState必然是null。
  • 之前Bloc的写法能正常运行,是因为BlocListener的回调是在组件构建完成后的副作用阶段触发,根本不会在同步build流程里执行导航操作。
  • 另外直接在build流程里写导航本身就是违规操作:Flutter要求build函数是纯函数,只负责返回组件,不能执行导航、弹窗这类副作用,不然只要组件触发重建就会重复执行跳转,后续就算解决了null问题也会出现页面乱跳的bug。
修复方案

直接用Riverpod官方提供的ref.listen处理状态变化对应的副作用即可,这个API的设计初衷就是干这个的——响应状态变化执行导航、弹Toast这类操作,回调触发时机安全,不会出现在build阶段拿不到NavigatorState的问题,也不会误触发重复跳转。

修正后的完整代码如下:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:workbench/app_pods.dart';
import 'package:workbench/app_router.dart';
import 'package:workbench/app_routes.dart';

class App extends StatelessWidget {
  App({Key? key}) : super(key: key);

  final _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        // 用listen监听认证状态变化,专门处理导航类副作用
        ref.listen<bool>(
          authProvider,
          (previous, next) {
            final navigator = _navigatorKey.currentState;
            // 空判断兜底,避免组件销毁阶段触发回调导致空指针
            if (navigator == null) return;
            if (next) {
              navigator.pushNamedAndRemoveUntil<void>(
                AppRoutes.home,
                (route) => false,
              );
            } else {
              navigator.pushNamedAndRemoveUntil<void>(
                AppRoutes.signin,
                (route) => false,
              );
            }
          },
          // 冷启动时直接根据初始认证状态跳转,不需要额外写启动页判断
          fireImmediately: true,
        );

        return MaterialApp(
            navigatorKey: _navigatorKey,
            debugShowCheckedModeBanner: false,
            initialRoute: AppRoutes.splash,
            onGenerateRoute: AppRouter.generateRoute,
            theme: ThemeData(
              colorSchemeSeed: const Color(0xFF243EA5),
            ),
            // builder只做全局组件包装,不要放业务导航逻辑
            builder: (context, child) {
              return child ?? const SizedBox.shrink();
            }
        );
      }
    );
  }
}

注意事项

  • 记住API职责分离:ref.watch只用来获取状态值构建Widget,ref.listen专门用来处理副作用,不要混着用。
  • 不要对currentState用!强制解包,加空判断兜底,极端场景(比如组件正在销毁)不会触发崩溃。
  • MaterialApp的builder回调只适合做全局组件包装(比如套全局Loading、做全局字体缩放适配),不要放业务逻辑。

内容的提问来源于stack exchange,提问作者Blue Waters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:21:40