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

Flutter中Firestore数据首次不显示及重复加载问题求助

问题描述

我是Dart编程新手,正在开发基于Firebase后端的基础App,实现认证功能与Firestore的CRUD操作。认证和新用户创建已成功,但使用FutureBuilder读取Firestore时遇问题:

  • 首页(认证后跳转页面)首次启动不显示内容
  • 热重载后可显示数据,但多次热重载会出现重复内容,页面累加所有请求的内容展示

首页文件

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_project_1/screens/home/read_data.dart';
import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final user = FirebaseAuth.instance.currentUser!;

  // 存储所有文档ID的列表
  List<String> documentIDs = [];

  Future getDocIDs() async {
    await FirebaseFirestore.instance.collection('Users').get().then(
          (snapshot) => snapshot.docs.forEach(
            (document) {
              print(document.reference);
              documentIDs.add(document.reference.id);
            },
          ),
        );
  }

  @override
  void initState() {
    getDocIDs();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple,
        title: Center(
          child: Text(
            textAlign: TextAlign.center,
            'Display dashboard',
            style: TextStyle(
              fontSize: 30,
              color: Colors.tealAccent.shade400,
            ),
          ),
        ),
        actions: [
          GestureDetector(
            onTap: () {
              FirebaseAuth.instance.signOut();
            },
            child: const Padding(
              padding: EdgeInsets.symmetric(horizontal: 10.0),
              child: Icon(
                Icons.logout_sharp,
              ),
            ),
          )
        ],
      ),
      backgroundColor: Colors.deepPurple.shade200,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Expanded(
              child: FutureBuilder<Object>(
                builder: (context, index) {
                  future:
                  getDocIDs();
                  return ListView.builder(
                    itemCount: documentIDs.length,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: ReadData(docIDs: documentIDs[index]),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

读数据文件

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class ReadData extends StatelessWidget {
  const ReadData({required this.docIDs, super.key});

  final String docIDs;

  @override
  Widget build (BuildContext context) {
    CollectionReference users = FirebaseFirestore.instance.collection('Users');

    return FutureBuilder<DocumentSnapshot>(
      future: users.doc(docIDs).get(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
          return Text('name: ${data['name']}');
        }
        return const Text('Loading......');
      },
    );
  }
}

解决方案

你的问题源于两个核心错误:FutureBuilder的误用,以及未清空列表导致重复数据累加。

1. 修复FutureBuilder的使用逻辑

你当前把future: getDocIDs()写在builder函数内部,会导致每次Widget重建(比如热重载)都重复触发数据请求,且FutureBuilder无法正确跟踪Future状态。正确做法是将Future实例保存在State变量中,避免重复执行。

2. 避免数据重复累加

每次调用getDocIDs()时,先清空documentIDs列表,否则每次请求都会往列表里追加新ID,导致内容重复。

修改后的首页代码

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_project_1/screens/home/read_data.dart';
import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final user = FirebaseAuth.instance.currentUser!;
  List<String> documentIDs = [];
  late Future<void> _docIDsFuture; // 保存Future实例,避免重复触发请求

  Future getDocIDs() async {
    documentIDs.clear(); // 请求前清空列表
    final snapshot = await FirebaseFirestore.instance.collection('Users').get();
    for (var doc in snapshot.docs) {
      documentIDs.add(doc.id);
    }
  }

  @override
  void initState() {
    _docIDsFuture = getDocIDs(); // 初始化时保存Future
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple,
        title: const Center(
          child: Text(
            'Display dashboard',
            textAlign: TextAlign.center,
            style: TextStyle(
              fontSize: 30,
              color: Colors.tealAccent,
            ),
          ),
        ),
        actions: [
          GestureDetector(
            onTap: () => FirebaseAuth.instance.signOut(),
            child: const Padding(
              padding: EdgeInsets.symmetric(horizontal: 10.0),
              child: Icon(Icons.logout_sharp),
            ),
          )
        ],
      ),
      backgroundColor: Colors.deepPurple.shade200,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Expanded(
              child: FutureBuilder<void>(
                future: _docIDsFuture, // 使用预存的Future实例
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const Center(child: Text('Loading......'));
                  } else if (snapshot.hasError) {
                    return Center(child: Text('加载失败: ${snapshot.error}'));
                  } else {
                    return ListView.builder(
                      itemCount: documentIDs.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: ReadData(docIDs: documentIDs[index]),
                        );
                      },
                    );
                  }
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

额外优化建议

  • 可使用StreamBuilder替代FutureBuilder,实时监听Firestore数据变化,数据更新时页面自动刷新。
  • 在ReadData组件中添加错误处理逻辑,避免snapshot.data为空时触发异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:20:12