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

Flutter中setState首次点击无法更新游戏列表问题求助

问题:首次点击“获取更多”无法更新游戏列表,二次点击才生效

页面展示游戏列表,点击“获取更多”按钮加载下一页数据,但首次点击时列表无变化,第二次点击才能成功更新。尝试在setState后调用_loadData(),问题依旧。

提供的代码

HomePage State代码

class _HomePageState extends State<HomePage> {
  bool _isLoading = true;
  int _currentPage = 0;

  @override
  void initState() {
    super.initState();
    Provider.of<GameController>(
      context,
      listen: false,
    ).loadGames(_currentPage).then((value) {
      setState(() => _isLoading = false);
    });
  }

  _loadData() async {
    await Provider.of<GameController>(
      context,
      listen: false,
    ).loadGames(_currentPage);
  }

  @override
  Widget build(BuildContext context) {
    final gameController = Provider.of<GameController>(context, listen: false);
    final List<Game> loadGames = gameController.games;
    final deviceSize = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Games'),
        centerTitle: true,
        actions: const [LogoutButton()],
      ),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : Column(
              mainAxisSize: MainAxisSize.max,
              children: [
                Expanded(
                  child: SizedBox(
                    height: deviceSize.height * 0.75,
                    child: SingleChildScrollView(
                      child: Column(
                        children: [
                          GameList(loadGames),
                          Container(
                            margin: const EdgeInsets.only(bottom: 10.0),
                            child: ElevatedButton(
                              onPressed: () {
                                print(_currentPage);
                                setState(() {
                                  _currentPage++;
                                  _loadData();
                                });
                                print(_currentPage);
                              },
                              child: const Text('Get more...'),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
    );
  }
}

GameController的loadGames函数

Future<void> loadGames(int currentPage) async {

    final url = '${Constants.urlGame}?page=$currentPage';
    SharedPreferences prefs = await SharedPreferences.getInstance();
    final token = prefs.getString('token');
    final response = await http.get(
      Uri.parse(url),
      headers: {'Authorization': '$token'},
    );

    if (response.statusCode == 200) {
      final jsonResponse = jsonDecode(response.body);
      final gameList = GameList.fromJson(jsonResponse);
      final List<Game> games = gameList.games;
      _games.clear();
      _games.addAll(games);
      notifyListeners();
    } else {
      print(
        response.statusCode,
      );
    }
  }

问题根源

  1. 数据加载逻辑错误:loadGames里的_games.clear()会清空已有数据,每次加载新页都是替换而非追加,违背“获取更多”的需求。
  2. 页面未监听Provider变化:build方法中用listen: false获取GameController,导致notifyListeners()触发时页面不会重新构建,无法感知数据更新。
  3. 异步调用顺序问题:setState中同步调用异步的_loadData(),setState立即完成但数据加载未结束,页面不会等待加载完成就刷新,首次点击后数据未更新导致无变化。

修复方案

1. 修改loadGames实现数据追加

移除_games.clear(),直接追加新页数据:

Future<void> loadGames(int currentPage) async {
  final url = '${Constants.urlGame}?page=$currentPage';
  SharedPreferences prefs = await SharedPreferences.getInstance();
  final token = prefs.getString('token');
  final response = await http.get(
    Uri.parse(url),
    headers: {'Authorization': '$token'},
  );

  if (response.statusCode == 200) {
    final jsonResponse = jsonDecode(response.body);
    final gameList = GameList.fromJson(jsonResponse);
    final List<Game> games = gameList.games;
    // 移除clear,直接追加新数据
    _games.addAll(games);
    notifyListeners();
  } else {
    print(response.statusCode);
  }
}

2. 让页面监听Provider数据变化

去掉listen: false,使页面能监听数据更新自动刷新:

@override
Widget build(BuildContext context) {
  // 监听GameController的变化,数据更新时自动重建页面
  final gameController = Provider.of<GameController>(context);
  final List<Game> loadGames = gameController.games;
  final deviceSize = MediaQuery.of(context).size;

  // 后续代码保持不变
}

3. 修正按钮点击的异步逻辑

无需在setState内调用异步函数,先递增页码再加载数据,页面会因Provider监听自动刷新:

ElevatedButton(
  onPressed: () async {
    _currentPage++;
    await _loadData();
  },
  child: const Text('Get more...'),
),

4. 可选:添加加载状态防重复点击

添加_isLoadingMore变量,避免用户重复点击:

// 在State类中添加变量
bool _isLoadingMore = false;

// 修改_loadData函数
_loadData() async {
  if (_isLoadingMore) return;
  setState(() {
    _isLoadingMore = true;
  });
  await Provider.of<GameController>(
    context,
    listen: false,
  ).loadGames(_currentPage);
  setState(() {
    _isLoadingMore = false;
  });
}

// 修改按钮
ElevatedButton(
  onPressed: _isLoadingMore ? null : () async {
    _currentPage++;
    await _loadData();
  },
  child: _isLoadingMore 
      ? const CircularProgressIndicator(color: Colors.white) 
      : const Text('Get more...'),
),

完成以上修改后,首次点击“获取更多”即可正确追加新游戏数据,页面自动刷新显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:06:56