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

Flutter AutoRoute声明式路由AppState变更触发setState during build报错

问题根因

这个setState() or markNeedsBuild() called during build异常是状态更新和路由重建的时机冲突导致的:
你在AutoRouterDelegate.declarative的routes回调中用context.watch<AppState>()监听状态,AppState更新时会触发外层Builder重绘,重绘过程中同步计算新路由列表,AutoRoute收到新路由后会立即通知Router组件重建,而此时还处在当前Widget的build流程中,就触发了Flutter的异常检查。

修复方案

方案1 调整声明式路由的状态监听逻辑

用Selector包裹路由相关逻辑,仅监听需要的状态字段,避免在路由生成回调中同步触发状态更新:

// 替换你原有的build方法即可
@override
Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider<AppState>(create: (_) => _appState),
    ],
    child: Selector<AppState, (bool initialized, bool isLogin)>(
      selector: (ctx, state) => (state.initialized, state.loginState),
      builder: (context, state, child) {
        final targetRoutes = [
          if (!state.initialized) const SplashRoute()
          else if (!state.isLogin) const LogInRoute()
          else const HomeRoute()
        ];
        return MaterialApp.router(
          title: 'My App',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          routerDelegate: AutoRouterDelegate.declarative(
            _appRouter,
            routes: (_) => targetRoutes,
          ),
          routeInformationParser: _appRouter.defaultRouteParser(),
        );
      },
    ),
  );
}

方案2 手动控制路由跳转(更稳定)

放弃声明式路由的写法,手动监听AppState变化,将路由更新时机延后到当前帧绘制结束后执行,完全避免build过程中触发重建的问题:

class _MyAppState extends State<MyApp> {
  late AppRouter _appRouter;
  late AppState _appState;

  @override
  void initState() {
    super.initState();
    _appRouter = AppRouter();
    _appState = AppState();
    // 注册状态变化监听
    _appState.addListener(_updateRouteOnStateChange);
  }

  @override
  void dispose() {
    // 移除监听避免内存泄漏
    _appState.removeListener(_updateRouteOnStateChange);
    super.dispose();
  }

  void _updateRouteOnStateChange() {
    // 延后到当前帧绘制结束后执行路由切换
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!_appState.initialized) {
        _appRouter.replaceAll([const SplashRoute()]);
      } else if (!_appState.loginState) {
        _appRouter.replaceAll([const LogInRoute()]);
      } else {
        _appRouter.replaceAll([const HomeRoute()]);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<AppState>(create: (_) => _appState),
      ],
      child: MaterialApp.router(
        title: 'My App',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        routerDelegate: _appRouter.delegate(),
        routeInformationParser: _appRouter.defaultRouteParser(),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Ishanga Vidusha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:27:05