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

Flutter Riverpod StateNotifierProvider始终处于加载状态求助

解决Riverpod StateNotifier一直处于加载状态的问题

核心问题分析

  • search方法中错误使用ref.read(...)结合when处理异步结果:when是同步方法,无法等待Future完成,且未将获取到的数据赋值给state
  • 页面初始化时未自动触发热门桌游列表加载
  • API调用逻辑有缺陷:当查询参数为空时,URL仍携带name=参数,不符合API获取热门列表的规则

修正步骤及代码

1. 修复RemoteApi的API调用逻辑

当查询参数为空时,不添加name参数,确保API返回热门桌游列表:

final boardGamesListProvider = FutureProvider.family.autoDispose<List<BoardGame>, String>((ref, request) => RemoteApi().getBoardGames(request));

class RemoteApi {
  Future<List<BoardGame>> getBoardGames(String request) async {
    try {
      // 根据查询参数是否为空构造请求URL
      String url = 'https://api.boardgameatlas.com/api/search?client_id=JLBr5npPhV';
      if (request.isNotEmpty) {
        url += '&name=$request';
      }
      final response = await Dio().get(url);

      if (response.statusCode == 200) {
        final data = Map<String, dynamic>.from(response.data);
        final results = List<Map<String, dynamic>>.from(data['games'] ?? []);
        return results.map((e) => BoardGame.fromMap(e)).toList();
      }
      return [];
    } on DioError catch (err) {
      print(err);
      throw ErrorHandler(message: err.response?.statusMessage ?? '请求出错!');
    } on SocketException catch (err) {
      print(err);
      throw const ErrorHandler(message: '请检查网络连接。');
    }
  }
}

2. 修复StateNotifier的逻辑

改用await等待Future结果返回,并在初始化时自动加载热门列表:

final boardGamesListControllerProvider =
    StateNotifierProvider<BoardGameList, AsyncValue<List<BoardGame>>>((ref) {
  final controller = BoardGameList(const AsyncValue.data([]), ref);
  // 初始化时自动加载热门桌游
  controller.search('');
  return controller;
});

class BoardGameList extends StateNotifier<AsyncValue<List<BoardGame>>> {
  BoardGameList(AsyncValue<List<BoardGame>> items, this.ref) : super(items);

  final Ref ref;

  Future<void> search(String request) async {
    state = const AsyncValue.loading();
    try {
      // 等待FutureProvider返回结果
      final data = await ref.read(boardGamesListProvider(request).future);
      state = AsyncValue.data(data);
    } catch (err, stackTrace) {
      state = AsyncValue.error(err, stackTrace: stackTrace);
    }
  }
}

3. 优化搜索页面细节

使用Hook管理文本控制器,避免重复创建:

class SearchGameScreen extends HookConsumerWidget {
  const SearchGameScreen({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 用Hook创建文本控制器,避免每次build重建
    final searchController = useTextEditingController();
    final boardGameListAsync = ref.watch(boardGamesListControllerProvider);
    
    return Scaffold(
      body: Column(
        children: [
          Row(
            children: [
              Expanded(
                child: Container(
                  padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
                  margin: const EdgeInsets.only(bottom: 2),
                  child: TextFormField(
                    controller: searchController,
                    decoration: const InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: '搜索桌游',
                    ),
                  ),
                ),
              ),
              Container(
                height: 50,
                padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
                margin: const EdgeInsets.only(bottom: 2),
                child: ElevatedButton(
                  child: const Text('搜索', style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    ref.read(boardGamesListControllerProvider.notifier)
                        .search(searchController.text.trim());
                  },
                ),
              ),
            ],
          ),
          Expanded(
            child: boardGameListAsync.when(
              data: (boardGamesList) {
                return BoardGamesList(boardGames: boardGamesList);
              },
              loading: () => const Center(child: CircularProgressIndicator()),
              error: (error, _) => ErrorScreen(message: error.toString()),
            ),
          )
        ],
      ),
    );
  }
}

// BoardGamesList和BoardGameItemWidget代码保持不变

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:35:20