使用Flutter Hooks useEffect刷新Riverpod FutureProvider无加载状态如何解决
问题原因
- 代码存在变量名笔误:
useProvider(myFutureProvider)返回的是AsyncValue类型的请求结果,而context.refresh要求传入的是Provider本身(也就是你定义的myFutureProvider),你代码里错把请求结果当成Provider传入了refresh方法,同时return处的searchFetch和你定义的变量名不一致,属于基础笔误。 useEffect执行时机在Widget当前帧构建完成之后:当someKeys变更触发组件重构建时,会先用旧的请求结果完成一次UI渲染(直接走data分支),之后才会执行useEffect内的刷新逻辑。AsyncValue.when默认跳过刷新时的loading状态:when方法默认skipLoadingOnRefresh = true,当Provider已有旧数据、触发刷新时会继续保留旧数据展示,不会切换到loading状态,直到新的请求完成。
修复方案
方案1:快速修复现有逻辑
修正笔误,同时修改when方法的参数,关闭刷新时跳过loading的配置:
@hwidget Widget someWidget(BuildContext context) { // 把请求结果命名和Provider本身区分开 final searchFetch = useProvider(myFutureProvider); useEffect(() { // refresh传入Provider本身,不是请求结果 context.refresh(myFutureProvider); }, [someKeys]); return searchFetch.when( // 关闭刷新时跳过loading的配置 skipLoadingOnRefresh: false, data: (data) => TextButton( onPressed: () { context.refresh(myFutureProvider); }, child: const Text('refresh') ), loading: () => const Text('Loading...'), error: (error, stack) => const Text('Error.')); }
方案2:更符合Riverpod设计的优化写法
不用手动写useEffect监听刷新,直接用family修饰符把someKeys作为Provider的参数,参数变化时Provider会自动重新请求,逻辑更简洁:
首先定义Provider的时候用family:
final myFutureProvider = FutureProvider.family<YourDataType, YourKeyType>((ref, key) async { // 把someKeys传入这里,用key作为请求参数 return yourApiRequest(key); });
组件代码修改为:
@hwidget Widget someWidget(BuildContext context) { // 直接把someKeys传入Provider final searchFetch = useProvider(myFutureProvider(someKeys)); return searchFetch.when( skipLoadingOnRefresh: false, data: (data) => TextButton( onPressed: () { // 刷新对应参数的Provider context.refresh(myFutureProvider(someKeys)); }, child: const Text('refresh') ), loading: () => const Text('Loading...'), error: (error, stack) => const Text('Error.')); }
内容的提问来源于stack exchange,提问作者Kataoka Hiroki
相关产品推荐
相关产品推荐

