【问题标题】:Flutter Riverpod StateNotifierProvider Async value still loadingFlutter Riverpod StateNotifierProvider 异步值仍在加载
【发布时间】:2022-10-25 19:36:21
【问题描述】:

我是 Flutter 的新手。我使用 Riverpod 状态管理库。我正在调用远程 API 来获取棋盘游戏列表。如果我没有将参数传递给我的查询,它会返回一个流行游戏列表,如果我传递一个游戏名称参数,它会返回一个包含名称中参数的游戏列表。 因此,我想在用户登陆页面时显示热门游戏列表,并在用户通过在搜索栏中输入游戏名称来搜索游戏时更新列表。问题:我的 StateNotifier 不工作并保持在加载状态。任何帮助将不胜感激,我真的迷路了。

这是我的remote_api.dart

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

class RemoteApi {

  Future<List<BoardGame>> getBoardGames(String request) async {
    // Appel WS
    try {
      final response = await Dio().get('https://api.boardgameatlas.com/api/search?name=$request&client_id=JLBr5npPhV');

      if (response.statusCode == 200) {
        final data = Map<String, dynamic>.from(response.data);
        final results = List<Map<String, dynamic>>.from(data['games']);
        if (results.isNotEmpty) {
          return results.map((e) => BoardGame.fromMap(e)).toList();
        }
      }
      return [];
    } on DioError catch (err) {
      print(err);
      throw ErrorHandler(message: err.response?.statusMessage ?? 'Something went wrong!');
    } on SocketException catch (err) {
      print(err);
      throw const ErrorHandler(message: 'Please check your connection.');
    }
  }
}

我的search_game_controller.dart:

final boardGamesListControllerProvider =
    StateNotifierProvider<BoardGameList, AsyncValue<List<BoardGame>>>((ref) {
  return BoardGameList(const AsyncValue.data([]), ref);
});

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();
    ref.read(boardGamesListProvider(request)).when(data: (data) {
      AsyncValue.data(data);
    }, error: (err, stackTrace) {
      state = AsyncValue.error(err, stackTrace: stackTrace);
    }, loading: () {
      state = const AsyncValue.loading();
    });
  }
}

我的search_game_screen.dart:

class SearchGameScreen extends HookConsumerWidget {
  const SearchGameScreen({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final searchController = TextEditingController();
    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: 'Search a game',
                    ),
                  ),
                ),
              ),
              Container(
                height: 50,
                padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
                margin: const EdgeInsets.only(bottom: 2),
                child: ElevatedButton(
                  child: const Text('Search',
                      style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    ref
                    .read(boardGamesListControllerProvider.notifier).search(searchController.text);
                    print(boardGameListAsync);
                  },
                ),
              ),
            ],
          ),
          Expanded(
            child: boardGameListAsync
                .when(
                  data: (boardGamesList) {
                    return BoardGamesList(boardGames: boardGamesList);
                  },
                  loading: () =>
                      const Center(child: CircularProgressIndicator()),
                  error: (error, _) => ErrorScreen(message: error.toString()),
                ),
          )
        ],
      ),
    );
  }
}

class BoardGamesList extends HookConsumerWidget {
  const BoardGamesList({Key? key, required this.boardGames}) : super(key: key);
  final List<BoardGame> boardGames;
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ListView.builder(
      itemCount: boardGames.length,
      itemBuilder: (context, index) {
        final boardGame = boardGames[index];
        return BoardGameItemWidget(boardGame: boardGame);
      },
    );
  }
}

class BoardGameItemWidget extends ConsumerWidget {
  const BoardGameItemWidget({Key? key, required this.boardGame})
      : super(key: key);
  final BoardGame boardGame;
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return GestureDetector(
      onTap: () {
        context.go('/game/details/${boardGame.idFromApi}');
      },
      child: Card(
        margin: const EdgeInsets.all(8),
        elevation: 8,
        child: Row(
          children: [
            Hero(
              tag: boardGame.title,
              child: CachedNetworkImage(
                imageUrl: boardGame.image,
                placeholder: (context, url) =>
                    const Center(child: CircularProgressIndicator()),
                errorWidget: (context, url, error) => const Icon(Icons.error),
                width: 100,
                height: 100,
                fit: BoxFit.cover,
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Container(
                      padding: const EdgeInsets.only(bottom: 8),
                      child: Text(boardGame.title,
                          style: const TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 20))),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

谢谢 !

【问题讨论】:

  • 单击“搜索”按钮时是否遇到此问题?
  • 是的,在初始化时我没有列表,也没有加载状态,除了搜索栏外,屏幕上什么也没有。从我启动搜索的那一刻起,加载状态就不会停止
  • 我回答了这个问题。
  • 嘿 @Colembole - 你为什么要使用 AsyncValue<T>?你不需要它,你知道吗?
  • 嘿@DishankJindal,不,我不知道,正如我解释的那样,我是 Flutter 初学者,我很迷茫。如果您有替代解决方案,请与我分享,这将非常有帮助。

标签: flutter dart riverpod flutter-riverpod


【解决方案1】:

试试下面的代码:

final boardGamesListControllerProvider =
    StateNotifierProvider<BoardGameList, AsyncValue<List<BoardGame>>>((ref) {
  return BoardGameList(const AsyncValue.data([]), ref);
});

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();
    ref.read(boardGamesListProvider(request)).when(data: (data) {
      state = AsyncValue.data(data);
    }, error: (err, stackTrace) {
      state = AsyncValue.error(err, stackTrace: stackTrace);
    }, loading: () {
      state = const AsyncValue.loading();
    });
  }
}

【讨论】:

  • 不工作,搜索没有加载状态,什么都没有。此外,我看不出你有什么变化。
  • 它会什么都找不到吗?
  • 我不确定是否理解你的问题,但我看不出有什么区别,而且我的屏幕是一样的。如果是第一次初始化,即使搜索也没有发生任何事情。但是如果我切换屏幕,例如回到主页,然后返回搜索游戏屏幕,它就会加载并保持加载我所做的任何事情。
  • 我的意思是,可能找不到任何东西
  • 我的意思是,也许找不到棋盘游戏
【解决方案2】:

我找到了解决方案:

我的屏幕:

class SearchGameScreen extends HookConsumerWidget {
  const SearchGameScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final searchController = TextEditingController();
    AsyncValue<List<BoardGame>> search = 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: 'Search a game',
                    ),
                  ),
                ),
              ),
              Container(
                height: 50,
                padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
                margin: const EdgeInsets.only(bottom: 2),
                child: ElevatedButton(
                  child: const Text('Search',
                      style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    ref.read(boardGamesListControllerProvider.notifier).search(searchController.text);
                  },
                ),
              ),
            ],
          ),
          Expanded(
            child: search.when(
              data: (data) => BoardGamesList(boardGames: data),
              loading: () => const Center(
                  child: CircularProgressIndicator(),
              ),
              error: (error, _) => const Center(
                child: Text('Uh oh... Something went wrong...',
                    style: TextStyle(color: Colors.white)),
              ),
            )
          )
        ],
      ),
    );
  }
}

我的视图模型:

final boardGamesListControllerProvider =
StateNotifierProvider<BoardGameList, AsyncValue<List<BoardGame>>>((ref) {
  return BoardGameList(const AsyncValue.data([]), ref);
});

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

  final Ref ref;

  Future<void> init() async {
    state = const AsyncValue.loading();
    try {
      final search = await ref.watch(boardGamesListProvider('').future);
      state = AsyncValue.data(search);
    } catch (e) {
      state = AsyncValue.error(e);
    }
  }

  Future<void> search(String request) async {
    state = const AsyncValue.loading();
    try {
      final search = await ref.watch(boardGamesListProvider(request).future);
      state = AsyncValue.data(search);
    } catch (e) {
      state = AsyncValue.error(e);
    }
  }
}

【讨论】:

    猜你喜欢
    • 2021-03-24
    • 2021-01-24
    • 2022-08-14
    • 2023-01-25
    • 1970-01-01
    • 2021-01-28
    • 2019-10-29
    • 2021-08-17
    • 2019-02-06
    相关资源
    最近更新 更多