GoRouter Web端热重载时Extra丢失致应用异常,如何解决?
问题描述
我定义了如下GoRouter路由:
GoRoute( path: Screen.classDetail.path, builder: (context, state) => AdminClassScreen( classItem: state.extra as Class, ), ),
通过以下方式导航到该路由:
router.push(Screen.classDetail.path, extra: extra);
在Web端执行热重载时,传入的extra对象不会被保留,导致应用进入异常状态。请问有什么可行的解决办法?
解决办法
方案1:将数据编码到路由路径/查询参数中
把Class对象的关键标识(比如ID)放到路径参数或查询参数里,热重载后通过标识重新从数据源(API、本地缓存等)获取完整数据,彻底摆脱对extra的依赖。
修改路由定义:
GoRoute( path: '${Screen.classDetail.path}/:classId', builder: (context, state) { final classId = state.pathParameters['classId']!; // 从数据源获取Class对象,示例为模拟方法 final classItem = fetchClassById(classId); return AdminClassScreen(classItem: classItem); }, ),
导航时传递ID而非完整对象:
router.push('${Screen.classDetail.path}/${extra.id}');
方案2:用全局状态管理临时存储数据
将需要传递的Class对象存入全局状态容器(如Provider、Riverpod、Bloc),导航时仅跳转路由,页面从全局状态中读取数据。热重载后全局状态通常会保留,避免数据丢失。
以Riverpod为例:
- 定义临时状态Provider:
final tempClassProvider = StateProvider<Class?>((ref) => null);
- 导航前存入状态:
ref.read(tempClassProvider.notifier).state = extra; router.push(Screen.classDetail.path);
- 路由页面获取数据:
GoRoute( path: Screen.classDetail.path, builder: (context, state) { final classItem = ref.watch(tempClassProvider)!; // 页面加载后清空临时状态,防止污染其他场景 WidgetsBinding.instance.addPostFrameCallback((_) { ref.read(tempClassProvider.notifier).state = null; }); return AdminClassScreen(classItem: classItem); }, ),
方案3:自定义路由extra缓存
创建全局缓存类保存路由extra数据,热重载后优先从缓存读取, fallback 到state.extra。
- 实现缓存类:
class RouteExtraCache { static final RouteExtraCache _instance = RouteExtraCache._(); RouteExtraCache._(); factory RouteExtraCache() => _instance; final Map<String, dynamic?> _cache = {}; void save(String path, dynamic extra) => _cache[path] = extra; dynamic? get(String path) => _cache[path]; }
- 导航时保存
extra:
RouteExtraCache().save(Screen.classDetail.path, extra); router.push(Screen.classDetail.path, extra: extra);
- 修改路由builder:
GoRoute( path: Screen.classDetail.path, builder: (context, state) { final classItem = state.extra as Class? ?? RouteExtraCache().get(Screen.classDetail.path) as Class; return AdminClassScreen(classItem: classItem); }, ),
内容的提问来源于stack exchange,提问作者Michael Jajou
相关产品推荐
相关产品推荐

