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
相关产品推荐
相关产品推荐

