You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确结合Riverpod与Material 3的SearchAnchor解决建议不更新问题?

问题分析与解决方案

核心问题

  1. 防抖时间设置错误:你在suggestionsProvider中使用了Duration(microseconds: 250),250微秒几乎是瞬时执行,无法起到防抖作用,会导致频繁触发搜索请求,甚至可能阻塞UI更新。
  2. SearchAnchor建议列表未响应状态变化:当前suggestionsBuilder仅在build阶段获取一次suggestionState,当Riverpod状态更新时,已弹出的建议视图不会自动刷新,导致新输入的文本无法触发建议更新。
  3. SearchController监听存在冗余更新:每次输入都会触发searchProvider状态设置,即使文本未变化,可能导致不必要的状态重建。

具体修复步骤

1. 修正防抖时间

将suggestionsProvider中的延迟时间从微秒改为毫秒,实现合理的搜索防抖:

@riverpod
Stream<List<String>> suggestions(SuggestionsRef ref) async* {
  await Future.delayed(const Duration(milliseconds: 250)); // 改为毫秒级防抖
  final query = ref.watch(searchProvider);
  final noteUseCase = await ref.watch(noteUseCaseProvider.future);
  yield* noteUseCase.getNoteSuggestions(query: query);
}

2. 让SuggestionsBuilder响应状态变化

修改SearchAnchor的suggestionsBuilder,使用Consumer包裹逻辑,确保建议列表能实时监听Riverpod状态变化:

suggestionsBuilder: (context, controller) {
  return Consumer(
    builder: (context, ref, child) {
      final suggestionState = ref.watch(suggestionsProvider);
      return suggestionState.when(
        data: (suggestions) => suggestions.map(
          (suggestion) => ListTile(
            title: Text(suggestion),
            onTap: () => controller.closeView(suggestion),
          ),
        ).toList(), // 转为List确保可遍历渲染
        error: (_, __) => [],
        loading: () => [const ListTile(title: Text("加载中..."))], // 添加加载提示
      );
    },
  );
},

3. 优化SearchController监听

避免重复设置相同的搜索文本到searchProvider,减少冗余状态更新:

@override
void initState() {
  super.initState();
  _searchController = SearchController()
    ..addListener(() {
      final currentText = _searchController.text;
      final currentQuery = ref.read(searchProvider);
      if (currentText != currentQuery) {
        ref.read(searchProvider.notifier).state = currentText;
      }
    });
}

4. 可选:简化搜索状态更新逻辑

可以直接在SearchBar的onChanged回调中更新搜索状态,替代SearchController的监听,代码更简洁:

onChanged: (newValue) {
  ref.read(searchProvider.notifier).state = newValue;
  controller.openView();
},

修改后可移除initState中的SearchController监听逻辑。

额外建议

  • 当搜索文本为空时,可在suggestionsProvider中直接返回空列表,减少不必要的请求:
final query = ref.watch(searchProvider);
if (query.isEmpty) yield [];
  • 如果不需要实时监听建议的流更新,可将suggestionsProvider改为FutureProvider,简化状态管理:
@riverpod
Future<List<String>> suggestions(SuggestionsRef ref) async {
  await Future.delayed(const Duration(milliseconds: 250));
  final query = ref.watch(searchProvider);
  if (query.isEmpty) return [];
  final noteUseCase = await ref.watch(noteUseCaseProvider.future);
  return await noteUseCase.getNoteSuggestions(query: query).first;
}

内容的提问来源于stack exchange,提问作者Fajra Risqulla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 19:02:05