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

使用Provider+FutureBuilder加载Firebase数据时build阶段调用setState报错如何解决?

错误原因

这个报错是因为你在Widget的build执行过程中触发了状态更新通知:
你直接在FutureBuilder的future参数中调用loadFollowers方法,该方法执行过程中会修改ProfileManager的状态并调用notifyListeners,而此时Widget还处于build流程中,状态更新会触发重绘,就会出现setState() or markNeedsBuild() called during build的错误。
另外你的loadFollowers方法存在异步逻辑漏洞:forEach中包裹的异步函数不会被等待,所有文档请求还没完成,方法就已经执行到loading = false并触发通知,数据加载逻辑本身也不符合预期。

修复步骤

1. 修复loadFollowers异步逻辑

将forEach异步遍历改为Future.wait等待所有请求完成,保证所有数据加载结束后再更新状态:

Future<void> loadFollowers(List profilesId) async {
  loading = true;
  notifyListeners();

  // 批量发起所有文档请求,等待全部返回
  final docList = await Future.wait(
    profilesId.map((id) => userRef.doc(id).get())
  );

  // 处理返回数据
  followersList.clear();
  for (var doc in docList) {
    followersList.add(Profile.fromDocument(doc));
  }

  loading = false;
  notifyListeners();
}

2. 调整页面加载触发时机

将页面改为StatefulWidget,在initState的帧回调中触发加载逻辑,避免在build过程中更新状态,同时去掉冗余的FutureBuilder(你已经用Consumer监听状态变化,不需要额外用FutureBuilder):

// 你的页面改为StatefulWidget
class FollowersPage extends StatefulWidget {
  final List followersId;
  const FollowersPage({super.key, required this.followersId});

  @override
  State<FollowersPage> createState() => _FollowersPageState();
}

class _FollowersPageState extends State<FollowersPage> {
  @override
  void initState() {
    super.initState();
    // 等当前帧build完成后再触发加载,避免build过程中更新状态
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Provider.of<ProfileManager>(context, listen: false).loadFollowers(widget.followersId);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        gradientBackground(),
        Scaffold(
          appBar: AppBar(
            brightness: Brightness.dark,
            elevation: 0,
            backgroundColor: Colors.transparent,
            centerTitle: true,
            title: const Text('Seguidores',
                style: TextStyle(color: Colors.white, fontFamily: 'MontSerrat')),
          ),
          backgroundColor: Colors.transparent,
          body: Consumer<ProfileManager>(
            builder: (_, profileManager, __) {
              if (profileManager.loading) {
                return circularProgress(Colors.white);
              }
              return ListView.builder(
                // 修复原来的取值错误,从profileManager取列表长度
                itemCount: profileManager.followersList.length,
                itemBuilder: (context, index) {
                  final follower = profileManager.followersList[index];
                  return GestureDetector(
                    onTap: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (_) => ProfileScreen(home: false)
                        )
                      );
                    },
                    child: Card(
                      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                      child: ListTile(
                        leading: CircleAvatar(
                          backgroundImage: CachedNetworkImageProvider(follower.picture ?? ''),
                        ),
                        title: Text(
                          follower.name ?? '',
                          style: const TextStyle(fontFamily: 'BebasNeue', fontSize: 20),
                        ),
                      ),
                    ),
                  );
                },
              );
            },
          ),
        )
      ],
    );
  }
}

其他注意事项

如果你需要保留FutureBuilder的写法,不要直接在future参数中调用方法,需要提前在initState中初始化Future变量,再把变量传给FutureBuilder的future参数,避免每次build都重新执行加载逻辑。

内容的提问来源于stack exchange,提问作者Ricardo Oscar Kanitz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 01:15:03