如何在Flutter Web中通过go_router传递Repository对象至下一路由
在Flutter Web中用go_router复用Repository实例的方案
针对你的需求——在/customers路由创建Repo实例后,在/customers/:id路由复用同一实例,且支持F5刷新页面后仍能获取实例,推荐两种可靠方案:
方案一:单例模式(最简单高效)
直接将Repo设计为单例,确保整个应用生命周期内只有一个实例,刷新后也会复用该实例:
class Repo { // 私有构造函数,禁止外部直接创建实例 Repo._(); // 类级单例实例 static final Repo instance = Repo._(); // 工厂构造函数,简化调用方式 factory Repo() => instance; void addEntity() {} void getEntity() {} void fetchEntities() {} }
在Bloc中使用单例(支持传入自定义实例,方便测试):
class ListViewBloc { final Repo _repo; // 允许传入Mock实例,默认使用全局单例 ListViewBloc({Repo? repo}) : _repo = repo ?? Repo(); } class EditDialogBloc { final Repo _repo; EditDialogBloc({Repo? repo}) : _repo = repo ?? Repo(); }
go_router路由配置无需额外处理,正常跳转即可:
final router = GoRouter( routes: [ GoRoute( path: '/customers', builder: (context, state) => CustomersPage(), routes: [ GoRoute( path: ':id', builder: (context, state) => CustomerDetailPage( id: state.pathParameters['id']!, ), ), ], ), ], );
方案二:全局依赖注入容器(适合复杂项目)
如果项目需要更灵活的依赖管理(比如多环境切换、动态替换实例),可以用get_it这类依赖注入库:
1. 初始化全局容器
final getIt = GetIt.instance;
2. 在列表路由注册Repo实例
进入/customers路由时初始化Repo,并注册为单例,避免重复创建:
class CustomersPage extends StatelessWidget { @override Widget build(BuildContext context) { if (!getIt.isRegistered<Repo>()) { getIt.registerSingleton<Repo>(Repo()); } final repo = getIt<Repo>(); final listBloc = ListViewBloc(repo: repo); return BlocProvider( create: (_) => listBloc, child: // 你的列表UI组件 ); } }
3. 详情路由获取全局Repo
在/customers/:id路由中直接从容器获取实例,刷新时如果容器为空则兜底创建:
class CustomerDetailPage extends StatelessWidget { final String id; const CustomerDetailPage({required this.id, super.key}); @override Widget build(BuildContext context) { final repo = getIt.isRegistered<Repo>() ? getIt<Repo>() : Repo(); final editBloc = EditDialogBloc(repo: repo); return BlocProvider( create: (_) => editBloc, child: // 你的详情UI组件 ); } }
关键注意事项
- 不要用go_router的
extra参数传递实例:Web页面刷新时extra参数会丢失,无法满足复用需求。 - 单例模式适合简单场景,依赖注入容器适合复杂项目,可根据实际需求选择。
内容的提问来源于stack exchange,提问作者BambinoUA
相关产品推荐
相关产品推荐

