结合Navigator 2.0处理导航状态应选用哪种Riverpod Provider?
核心集成逻辑
Navigator 2.0(Router API)的核心机制是RouterDelegate根据当前状态动态构建路由栈,和Riverpod的集成逻辑非常直接:将全局路由状态完全托管给Riverpod管理,在RouterDelegate中通过ref.watch监听路由状态变化,状态更新时自动触发路由栈重绘即可,不需要额外的桥接逻辑。
Provider选型对比
ChangeNotifierProvider适用场景
- 选择依据:你的导航逻辑需要维护多个可变属性(除路由栈外还要存跳转参数、动画配置、拦截状态等),且你更习惯原生端传统的观察者更新模式
- 优势:写法直观门槛低,调用
notifyListeners()即可触发更新,不需要强制状态不可变 - 劣势:没有状态修改的统一入口,可变状态容易出现难以追溯的逻辑bug,不适合多人协作的中大型项目
StateNotifierProvider适用场景
- 选择依据:希望路由状态为不可变类型,所有状态修改都走统一的方法入口,需要做路由行为埋点、日志追溯
- 优势:强制immutable状态,所有状态变更可追溯,逻辑更可控,适合中大型项目
- 劣势:需要单独定义状态类和StateNotifier子类,代码量稍高
更优选型推荐
如果是Riverpod 2.0及以上版本,官方首推NotifierProvider作为StateNotifierProvider的替代方案,写法更简洁,同时保留了不可变状态的所有优势,是当前处理导航状态的最优选择。
如果你的项目逻辑非常简单,仅需要维护路由栈列表,也可以直接用StateProvider<List<AppRoute>>,不需要定义任何类,直接修改state即可完成路由跳转,适合小型轻量化项目。
最简实现示例
// 1. 定义全局路由枚举 enum AppRoute { home, detail, settings } // 2. 定义不可变路由状态 @immutable class AppRouterState { final List<AppRoute> routeStack; final Map<String, dynamic>? currentRouteParams; const AppRouterState({required this.routeStack, this.currentRouteParams}); } // 3. 定义路由操作Notifier class AppRouterNotifier extends Notifier<AppRouterState> { @override AppRouterState build() => const AppRouterState(routeStack: [AppRoute.home]); // 压入新页面 void push(AppRoute route, {Map<String, dynamic>? params}) { state = AppRouterState( routeStack: [...state.routeStack, route], currentRouteParams: params, ); } // 弹出当前页面 void pop() { if (state.routeStack.length <= 1) return; state = AppRouterState( routeStack: state.routeStack.sublist(0, state.routeStack.length - 1), ); } // 替换当前页面 void replace(AppRoute route, {Map<String, dynamic>? params}) { state = AppRouterState( routeStack: [...state.routeStack.sublist(0, state.routeStack.length - 1), route], currentRouteParams: params, ); } } // 4. 定义路由Provider final appRouterProvider = NotifierProvider<AppRouterNotifier, AppRouterState>(AppRouterNotifier.new); // 5. 自定义RouterDelegate监听状态 class AppRouterDelegate extends RouterDelegate<AppRouterState> with ChangeNotifier, PopNavigatorRouterDelegateMixin { final WidgetRef ref; AppRouterDelegate(this.ref); @override final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); @override Widget build(BuildContext context) { final routerState = ref.watch(appRouterProvider); return Navigator( key: navigatorKey, pages: routerState.routeStack.map((route) { switch(route) { case AppRoute.home: return const MaterialPage(child: HomePage(), name: 'home'); case AppRoute.detail: return MaterialPage(child: DetailPage(params: routerState.currentRouteParams), name: 'detail'); case AppRoute.settings: return const MaterialPage(child: SettingsPage(), name: 'settings'); } }).toList(), onPopPage: (route, result) { if (!route.didPop(result)) return false; ref.read(appRouterProvider.notifier).pop(); return true; }, ); } @override Future<void> setNewRoutePath(AppRouterState configuration) async { state = configuration; } }
在业务页面中需要跳转时,直接调用ref.read(appRouterProvider.notifier).push(AppRoute.detail, params: {'id': 123})即可。
内容的提问来源于stack exchange,提问作者CKP78
相关产品推荐
相关产品推荐

