Flutter Riverpod:如何用搜索结果更新UI
问题:如何在Riverpod中切换FutureProvider数据源填充ListView
我正在使用名为defaultProvider的FutureProvider,通过ref.watch(defaultProvider)从API获取数据并填充ListView.Builder,代码如下:
ref.watch(countryProvider).when( data: (userData) { List<Article> itemList= userData.map((e) => e).toList(); return <Widget>(// 这里使用itemList[index].data ) }, error:(){}, loading(){} )
我希望用另一个FutureProvider——ref.read(searchProvider(value))返回的搜索结果重新填充该视图,两者均返回List<CustomType>类型。应用加载时显示defaultProvider的数据,搜索后替换为搜索结果,该如何实现?
附defaultProvider代码:
final defaultProvider= FutureProvider<List<CustomType>>((ref) => APIService(('queryparam', 'value'), apiUrl: URLConstants().urlType) .getData());
解决方案
核心思路是通过状态跟踪当前数据源类型,再动态选择对应的FutureProvider,以下是两种可行实现方式:
方案一:用状态Provider切换数据源
- 定义状态Provider记录搜索状态(null表示显示默认数据):
final searchStateProvider = StateProvider<String?>((ref) => null);
- 将搜索Provider改为家族Provider,接收搜索关键词参数:
final searchProvider = FutureProvider.family<List<CustomType>, String>((ref, query) => APIService(('search', query), apiUrl: URLConstants().searchUrl) .getData());
- UI层根据搜索状态动态选择要监听的Provider:
@override Widget build(BuildContext context, WidgetRef ref) { final searchQuery = ref.watch(searchStateProvider); // 根据搜索状态切换数据源 final asyncData = searchQuery != null ? ref.watch(searchProvider(searchQuery)) : ref.watch(defaultProvider); return asyncData.when( data: (dataList) { return ListView.builder( itemCount: dataList.length, itemBuilder: (context, index) { // 这里用dataList[index]渲染列表项 return ListTile(title: Text(dataList[index].title)); }, ); }, error: (error, stackTrace) => Text('加载失败:$error'), loading: () => const CircularProgressIndicator(), ); }
- 触发搜索/清空搜索的逻辑:
// 执行搜索 void onSearch(String query) { ref.read(searchStateProvider.notifier).state = query; } // 回到默认数据 void clearSearch() { ref.read(searchStateProvider.notifier).state = null; }
方案二:合并逻辑到单个FutureProvider
如果不想维护额外状态,可将默认数据与搜索数据的逻辑合并到一个家族Provider中:
final contentProvider = FutureProvider.family<List<CustomType>, String?>((ref, searchQuery) async { if (searchQuery != null && searchQuery.isNotEmpty) { // 返回搜索结果 return APIService(('search', searchQuery), apiUrl: URLConstants().searchUrl).getData(); } else { // 返回默认数据 return APIService(('queryparam', 'value'), apiUrl: URLConstants().urlType).getData(); } });
UI层直接监听这个合并后的Provider,搭配状态保存搜索关键词:
final searchQueryProvider = StateProvider<String?>((ref) => null); @override Widget build(BuildContext context, WidgetRef ref) { final searchQuery = ref.watch(searchQueryProvider); final asyncData = ref.watch(contentProvider(searchQuery)); return asyncData.when( data: (dataList) => ListView.builder(...), error: (e, s) => Text('出错了:$e'), loading: () => const CircularProgressIndicator(), ); }
触发搜索时更新searchQueryProvider的状态即可。
内容的提问来源于stack exchange,提问作者Ae Ri
相关产品推荐
相关产品推荐

