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

Flutter 中 setState 获取 Firestore 数据时如何在加载完成前显示进度指示器

实现方案

你当前的写法存在两个核心问题:

  • 直接将异步请求方法getQoutes()传入FutureBuilder的future参数,会在每次组件重绘时重复触发Firestore数据拉取,额外消耗读配额
  • 没有处理数据返回前的空值边界,布局嵌套存在滚动冲突问题

按照以下步骤修改即可实现加载态展示:

1. 调整状态变量与初始化逻辑

删除initState中直接调用的拉取方法,提前存储请求实例避免重复执行:

// 用户数据,初始为null
Map<String, dynamic>? userInfo;
// 存储数据拉取请求实例
late Future<void> quotesLoadFuture;

Future<void> getQoutes() async {
  final docSnap = await FirebaseFirestore.instance
      .collection('user')
      .doc(auth.currentUser!.uid)
      .get();
  userInfo = docSnap.data() as Map<String, dynamic>;
}

@override
void initState() {
  super.initState();
  // 仅在页面初始化时执行一次拉取
  quotesLoadFuture = getQoutes();
}

2. 重写build方法的状态判断逻辑

移除多余的滚动嵌套组件,通过FutureBuilder的连接状态判断渲染内容:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Some Quotes'),
      backgroundColor: Colors.deepOrange,
    ),
    body: FutureBuilder<void>(
      future: quotesLoadFuture,
      builder: (context, snapshot) {
        // 未加载完成状态:居中显示进度指示器
        if (snapshot.connectionState != ConnectionState.done) {
          return const Center(child: CircularProgressIndicator());
        }
        // 加载错误状态:显示错误提示
        if (snapshot.hasError) {
          return Center(child: Text('加载失败: ${snapshot.error}'));
        }
        // 加载完成:渲染数据列表
        final quotesList = userInfo?['quotes'] as List? ?? [];
        return Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Expanded(
              child: ListView.builder(
                // 不写死长度,取数据实际长度避免越界
                itemCount: quotesList.length,
                itemBuilder: (context, index) {
                  return Card_fun(quotesList[index]);
                },
              ),
            )
          ],
        );
      },
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () async {
        await popUpForm();
        // 表单操作后如果需要刷新数据,只需重新赋值future并触发setState
        setState(() {
          quotesLoadFuture = getQoutes();
        });
      },
    ),
  );
}

关键优化点

  • 禁止在FutureBuilder的future参数中直接调用异步方法,否则每次组件重绘(如键盘弹出、主题变化、setState触发)都会重新发起请求
  • 移除了原代码中多余的SingleChildScrollView和固定高度Container,ListView本身具备滚动能力,嵌套滚动组件会引发滑动冲突和布局溢出
  • 增加了数组空值判断,不再写死itemCount: 3,避免数据长度不足时触发数组越界报错
  • 如果需要实现Firestore数据实时同步,可以将FutureBuilder替换为StreamBuilder,直接监听文档快照流即可实现数据变更自动刷新,无需手动调用拉取方法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:00:59