使用go_router时,Flutter错误重定向至主页存在bug
问题原因分析
- 重复触发跳转:
ErrorStatelessView是无状态组件,每次build都会创建新的Timer,哪怕已经完成跳转,之前的Timer仍会执行,导致多次触发主页跳转;同时使用pushNamed会在路由栈中添加新页面而非替换当前错误页,路由栈堆积后操作时容易回到错误页,再次触发跳转循环。 - 全局错误处理设置不当:在
MaterialApp的builder中每次设置ErrorWidget.builder,会导致每次页面重建都覆盖错误处理逻辑,可能引发不必要的错误页渲染。 - 错误状态未重置:当
getSectionOffers返回错误状态时,跳转到主页后该状态仍未恢复,主页会再次渲染ErrorStatelessView,形成无限重定向循环。
解决方案
1. 修复错误页的跳转逻辑
将ErrorStatelessView改为有状态组件,确保Timer只执行一次,同时使用pushReplacementNamed替换当前路由,避免路由栈堆积:
class ErrorStatelessView extends StatefulWidget { const ErrorStatelessView({super.key}); @override State<ErrorStatelessView> createState() => _ErrorStatelessViewState(); } class _ErrorStatelessViewState extends State<ErrorStatelessView> { Timer? _redirectTimer; @override void initState() { super.initState(); // 仅在组件初始化时创建一次Timer _redirectTimer = Timer(const Duration(seconds: 3), () { if (mounted) { // 确保组件仍挂载时再执行跳转 context.pushReplacementNamed('home'); } }); } @override void dispose() { _redirectTimer?.cancel(); // 组件销毁时取消Timer,避免内存泄漏和无效跳转 super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 100, child: Image.asset('assets/images/oops.png')), const Text('Oops, it looks like something went wrong.'), const Text('You will be redirected back to the home'), const Text('page shortly.'), ], ), )); } }
2. 正确设置全局错误处理
在main函数中全局设置ErrorWidget.builder,而非在MaterialApp的builder中重复设置:
void main() { // 全局设置错误Widget ErrorWidget.builder = (FlutterErrorDetails errorDetails) { // 此处可添加错误日志逻辑 return const ErrorStatelessView(); }; runApp(const ProviderScope(child: MyApp())); }
同时修改主页面代码,移除MaterialApp builder中的ErrorWidget.builder设置:
@override Widget build(BuildContext context) { AsyncValue<HomeOffers> offers = ref.watch(getSectionOffers(sections)); Size size = MediaQuery.of(context).size; return offers.when( loading: () => const FormattedProgressIndicator(), error: (error, stackTrace) => const ErrorStatelessView(), data: (data) { return MaterialApp( builder: (context, child) { return Scaffold(body: offersDisplay(data, size)); }, home: const Scaffold(/* 主页内容 */), ); }, ); }
3. 确保跳转后错误状态重置
在跳转到主页时,触发getSectionOffers重新获取数据,避免主页仍处于错误状态:
class _ErrorStatelessViewState extends State<ErrorStatelessView> { Timer? _redirectTimer; late final WidgetRef ref; @override void initState() { super.initState(); ref = ProviderScope.containerOf(context); _redirectTimer = Timer(const Duration(seconds: 3), () { if (mounted) { // 重置getSectionOffers的状态,触发重新获取数据 ref.invalidate(getSectionOffers); context.pushReplacementNamed('home'); } }); } // ... dispose和build方法不变 }
额外注意事项
- 确保
getSectionOffersProvider在被invalidate后能正确重新发起请求,恢复正常状态。 - 可在
ErrorWidget.builder和AsyncValue.error中添加错误日志逻辑,方便后续问题排查。
内容的提问来源于stack exchange,提问作者Jelkimantis
相关产品推荐
相关产品推荐

