使用AsyncNotifier调用API存数据时,GoRouter的context.go无法跳转页面
问题分析与解决方案
核心问题
加载页面无法跳转的根本原因是使用了ref.read而非ref.watch监听状态:
ref.read仅获取当前状态一次,不会监听后续的状态变化;当AsyncNotifier的状态从loading变为data时,组件不会触发重建,自然不会执行data分支的跳转逻辑。
修复步骤及代码优化
1. 优化AsyncNotifier代码
利用Riverpod自动管理AsyncValue状态,移除手动设置state的冗余代码:
@riverpod class LoadingDataController extends _$LoadingDataController { List<Activite> activites = []; List<Devise> devises = []; @override Future<void> build() async { // Riverpod会自动将state设为loading,无需手动设置 await downloadData(); await insertData(); // 执行完成后自动切换为data状态 } Future<void> downloadData() async { devises = await ref.read(devisesRepositoryProvider).getDevises(); } Future<void> insertData() async { for (final devise in devises) { await ref.read(deviseDaoProvider).insert(devise); } } }
2. 修改加载组件的状态监听逻辑
将ref.read替换为ref.watch,并添加防重复跳转的标志位:
class _LoadingScreenState extends ConsumerState<LoadingScreen> { bool _hasNavigated = false; // 防止重复触发跳转 @override Widget build(BuildContext context) { // 使用watch监听状态变化,状态更新时自动重建组件 final loadingDataAsyncValue = ref.watch(loadingDataControllerProvider); return loadingDataAsyncValue.when( data: (_) { if (!_hasNavigated) { _hasNavigated = true; // 延迟跳转确保组件渲染完成 WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/banks'); }); } return const Scaffold(body: Center()); }, error: (error, stackTrace) { log("加载出错: $error"); log("堆栈信息: $stackTrace"); return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("加载失败,请重试"), ElevatedButton( onPressed: () => ref.invalidate(loadingDataControllerProvider), child: const Text("重试"), ), ], ), ), ); }, loading: () { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SpinKitSpinningLines( color: Colors.blue, size: 100, ), const SizedBox(height: 20), const ListTile( contentPadding: EdgeInsets.zero, title: Text( "Nous sommes entrain de configurer votre application", style: TextStyle( fontSize: 17, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), textAlign: TextAlign.center, ), subtitle: Text( "Veuillez patienter un moment...", style: TextStyle( fontSize: 13, fontWeight: FontWeight.w400, fontStyle: FontStyle.italic), textAlign: TextAlign.center, ), ) ], ), ), ); }, ); } }
关键说明
ref.watch会持续监听状态变化,当AsyncNotifier的任务完成后,组件会自动重建并进入data分支执行跳转。_hasNavigated标志位避免了组件因状态重复更新而多次触发跳转的问题。- AsyncNotifier的
build方法为异步函数时,Riverpod会自动管理loading/data/error三种状态,无需手动设置state。
内容的提问来源于stack exchange,提问作者Armando Sudi
相关产品推荐
相关产品推荐

