Flutter中SearchAnchor的SuggestionBuilder不随RiverPod Provider更新
问题修复方案
核心问题分析
- 旧数据提前显示:用户输入时,API请求还未完成,
suggestionBuilder直接使用了上次的searchResults旧数据。 - 建议列表不刷新:
SearchAnchor没有监听plannerState的状态变化,即使notifyListeners()触发,suggestionBuilder也不会重新执行。
具体修复步骤
1. 搜索前清空旧数据,避免显示历史结果
修改_searchStations方法,在发起API请求前先清空searchResults并通知状态更新,这样用户输入时会先看到空列表,而非旧数据:
Future<void> _searchStations(String query) async { // 搜索开始前清空旧数据,立即通知UI更新 searchResults = []; notifyListeners(); print("searching $query"); try { searchResults = await StationService().findStation(query); } catch (e) { // 处理API请求错误,兜底空列表 searchResults = []; } print("found ${searchResults.length}"); notifyListeners(); }
2. 让SearchAnchor监听状态变化
当前stationSearchBar没有监听plannerState的更新,需要用RiverPod的Consumer包裹,确保状态变化时SearchAnchor会重建,suggestionBuilder能获取最新的searchResults:
Widget stationSearchBar(BuildContext context) { return Consumer<PlannerViewModel>( builder: (context, plannerState, child) { // 避免重复添加Listener,只在首次构建时添加 WidgetsBinding.instance.addPostFrameCallback((_) { if (!plannerState.searchController.hasListeners) { plannerState.searchController.addListener(() { plannerState.searchInputChanged(plannerState.searchController.text); }); } }); return SearchAnchor( isFullScreen: false, searchController: plannerState.searchController, builder: (BuildContext context, SearchController controller) { return SearchBar( textCapitalization: TextCapitalization.none, controller: plannerState.searchController, onTap: () => controller.openView(), ); }, suggestionsBuilder: (BuildContext context, SearchController controller) { return plannerState.searchResults.map((Station result) { return ListTile( title: Text(result.names.values.first), ); }).toList(); }, ); }, ); }
3. 增加防抖逻辑,减少无效API请求
用户输入过程中会频繁触发searchInputChanged,建议添加防抖,避免每输入一个字符就发起请求:
在PlannerViewModel中添加防抖工具类和修改触发逻辑:
// 简单的防抖工具类 class Debounce { final int milliseconds; Timer? _timer; Debounce({required this.milliseconds}); void run(VoidCallback action) { _timer?.cancel(); _timer = Timer(Duration(milliseconds: milliseconds), action); } } // 在ViewModel中初始化防抖 final _debounce = Debounce(milliseconds: 300); void searchInputChanged(String query) { if (query.trim().isEmpty) { searchResults = []; notifyListeners(); return; } // 延迟300ms执行搜索,避免频繁请求 _debounce.run(() { _searchStations(query); }); }
修复原理
- 清空旧数据:确保搜索发起时UI先显示空状态,避免混淆用户。
Consumer监听:让SearchAnchor能感知plannerState的状态更新,自动重建并刷新建议列表。- 防抖:减少不必要的API请求,优化性能和后端压力。
内容的提问来源于stack exchange,提问作者Josian
相关产品推荐
相关产品推荐

