如何使用Riverpod Provider构建购物清单应用的实时搜索栏?
问题修复方案
1. 修复搜索文本状态更新
TextField的onChanged仅读取了provider但未更新状态,导致搜索文本变化时无法触发状态刷新:
TextField( onChanged: (value) { // 替换原错误写法,更新搜索文本状态 ref.read(searchTextProvider.notifier).state = value; }, decoration: const InputDecoration( labelText: 'Pesquisar', ), )
2. 修正Repository的模糊搜索逻辑
原getByName使用精确匹配name = ?,仅能找到完全一致的商品,且返回单个结果,不满足实时搜索需求:
// 修改返回类型为List,支持多结果返回 Future<List<Map<String, dynamic>>> getByName(String name) async { final map = await dbProvider.db.query( tableName, // 使用LIKE实现模糊匹配 where: 'name LIKE ?', // 前后添加%,匹配包含搜索文本的所有结果 whereArgs: ['%$name%'], ); return map; }
3. 调整ProductProvider的返回值与逻辑
原provider返回单个Map,无法适配多结果场景,且空搜索时应返回全部商品而非null:
// 修改返回类型为List<Map<String, dynamic>> final productProvider = FutureProvider<List<Map<String, dynamic>>>((ref) async { final searchText = ref.watch(searchTextProvider); final repository = Repository<Product>("Product"); if (searchText.isNotEmpty) { return await repository.getByName(searchText); } // 空搜索时返回全部商品,需确保Repository实现getAll方法 return await repository.getAll(); });
若Repository未实现getAll方法,补充如下:
Future<List<Map<String, dynamic>>> getAll() async { return await dbProvider.db.query(tableName); }
4. 修正UI层的数据处理逻辑
适配provider返回的List类型,移除原错误的单个Map处理逻辑:
Expanded( child: productsAsyncValue.when( data: (products) { if (products.isNotEmpty) { return ListView.builder( itemCount: products.length, itemBuilder: (context, index) { final product = products[index]; return ListTile( title: Text(product['name']), ); }, ); } else { return const Text('Nenhum resultado encontrado'); } }, loading: () => const CircularProgressIndicator(), error: (error, stackTrace) => Text('Erro: $error'), ), )
额外优化建议
- 添加搜索防抖(如延迟300ms执行查询),避免输入时频繁触发数据库请求,提升性能。
- 处理大小写敏感问题:可统一将存储的商品名称转为小写,或查询时将搜索文本与数据库字段统一大小写。
内容的提问来源于stack exchange,提问作者Leonardo Maito
相关产品推荐
相关产品推荐

