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

Flutter Web中GoRouter调用State Notifier触发构建报错问题求助

Flutter Web深度链接路由切换时SetState构建报错解决

问题背景

需要实现Flutter Web深度链接功能:用户访问www.myapp.com/#/projects/{projectShortId}时,GoRouter提取projectShortId参数,传入State Notifier加载对应项目详情。现有实现代码如下:

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationProvider: _router.routeInformationProvider,
      routeInformationParser: _router.routeInformationParser,
      routerDelegate: _router.routerDelegate,
    );
  }

  final GoRouter _router = GoRouter(
    initialLocation: '/login',
    routes: <GoRoute>[
      GoRoute(path: '/', builder: (context, state) => LoginSignupPage()),
      GoRoute(path: '/login', builder: (context, state) => LoginSignupPage()),
      GoRoute(
        path: '/projects/:projectShortId',
        builder: (context, state) {
          var projectShortId = state.params['projectShortId']!;
          return Consumer(
            builder: (context, ref, child) {
              ref
                .read(projectStateNotifierProvider.notifier)
                .setProjectFromCustomURI(projectShortId);
              return ViewProjectPage();
            },
          );
        },
      )
    ],
  );
}

报错现象

首次访问/projects/{userId1}正常,但切换到/projects/{userId2}时,触发构建错误:

Error: setState() or markNeedsBuild() called during build.
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49      throw_    
packages/flutter/src/widgets/framework.dart 4549:11                                                                            <fn>      
packages/flutter/src/widgets/framework.dart 4563:14
markNeedsBuild
packages/flutter_riverpod/src/framework.dart 287:5
[_debugCanModifyProviders]
packages/riverpod/src/framework/provider_base.dart 513:42                                                                      <fn>      
packages/riverpod/src/framework/provider_base.dart 337:7                                                                       setState  
packages/riverpod/src/state_notifier_provider/auto_dispose.dart 118:10                                                         listener  
packages/state_notifier/state_notifier.dart 225:23                                                                             set state 
packages/myapp_mvp/state/providers/project_state_provider/project_state_provider.dart 33:5
setProjectFromCustomURI

问题原因

报错本质是在Widget构建流程中直接修改了状态。切换路由时,Consumer的builder方法正在执行构建逻辑,此时调用setProjectFromCustomURI会立即修改State Notifier的状态,触发关联Widget的重建操作,而Flutter禁止在构建期间发起状态变更,因此抛出异常。

解决方案

方案1:延迟到当前帧构建完成后执行状态更新

使用WidgetsBinding.instance.addPostFrameCallback,将状态修改逻辑放到当前Widget帧构建完成后执行,避开构建流程:

GoRoute(
  path: '/projects/:projectShortId',
  builder: (context, state) {
    var projectShortId = state.params['projectShortId']!;
    return Consumer(
      builder: (context, ref, child) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          ref
            .read(projectStateNotifierProvider.notifier)
            .setProjectFromCustomURI(projectShortId);
        });
        return ViewProjectPage();
      },
    );
  },
)

方案2:监听路由参数变化触发更新(更优雅)

通过ref.listen监听路由参数的变化,仅当参数实际改变时才执行状态更新,避免重复操作:

GoRoute(
  path: '/projects/:projectShortId',
  builder: (context, state) {
    var projectShortId = state.params['projectShortId']!;
    return Consumer(
      builder: (context, ref, child) {
        // 监听参数变化,仅在参数更新时执行
        ref.listen(
          Provider((ref) => projectShortId),
          (prevId, newId) {
            if (prevId != newId) {
              ref
                .read(projectStateNotifierProvider.notifier)
                .setProjectFromCustomURI(newId);
            }
          },
        );
        return ViewProjectPage();
      },
    );
  },
)

额外优化建议

  • 若projectStateNotifierProvider使用了autoDispose修饰,确保路由切换时状态能正确重置或更新,避免残留旧数据。
  • 可将状态监听逻辑迁移到ViewProjectPage内部,让路由仅负责页面跳转,页面自身处理状态加载,职责划分更清晰。

内容的提问来源于stack exchange,提问作者Shazamo Morebucks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:36:51