使用 Firestore 在 Flutter 中加载配置文件数据的最佳方式是啥?

Posted

技术标签:

【中文标题】使用 Firestore 在 Flutter 中加载配置文件数据的最佳方式是啥?【英文标题】:What is the best way to load profile data in Flutter using Firestore?使用 Firestore 在 Flutter 中加载配置文件数据的最佳方式是什么? 【发布时间】:2021-06-30 08:52:34 【问题描述】:

我正在尝试使用 Firestore 加载配置文件数据。我不想每次点击主页都重新加载数据。

我想将此数据存储在类对象中,然后有一个刷新功能,用户可以在第一次初始化配置文件数据后手动调用。我想在调用“主页”小部件时执行此操作,传入我的“ProfileModel”的快照,但它会以相同的方式持续加载这些数据吗?

这是为所选索引调用的导航栏小部件类

  class SelectedNavigationBarItem extends StatelessWidget 
  FirebaseAuth auth;
  FirebaseFirestore firestore;
  final int currentIndex;
  bool hasBeenWelcomed = false;
  @override
  SelectedNavigationBarItem(
      @required this.auth, @required this.firestore, this.currentIndex);

  @override
  Widget build(BuildContext context) 
    List<Widget> _widgetOptions = <Widget>[
      HomeBarWelcome(
          auth: this.auth,
          firestore: this.firestore,
          welcomed: hasBeenWelcomed),
      Text("PlaceHolder1"),
      Text("Placeholder2"),
      Text("Placeholder3"),
    ];
    return _widgetOptions.elementAt(this.currentIndex);
  

我正在考虑一种使用 FutureBuilder 或 StreamBuilder 将配置文件数据快照传递给我拥有的 HomePage 类的方法。然后从那里,我会将该快照向下传递到小部件树,但如果我在我的第一个小部件中执行此操作,即 runApp() 调用的小部件,它会持续加载配置文件数据并继续调用 Firestore 以获取配置文件数据吗? 或者它会运行一次,然后放在 HomePage 类中,该类将在第一次 runApp() 调用中返回?

我想我只是想问一下小部件是如何被调用的? runApp() 是否被连续调用,然后每次调用都会沿着小部件路径遍历?还是调用一次,然后 Widget 类从那里处理 Flutter 应用程序的状态,每个 Widget 类根据该 Widget 类中调用的下一个小部件来控制状态? 抱歉,我确信这是一个相当混乱的帖子。但我只是在寻找加载这些数据的正确方法,因为我不希望重复调用 Firestore 来不必要地获取数据。

【问题讨论】:

您必须将您的策略​​从StatelessWidget 更改为StatefulWidget,并在initState 部分的State 类中加载资源并将其存储到一个字段中...... @Nima 我已经在这样做了,但我不想在每次调用状态更改时重新加载我的个人资料并调用 firestore。我希望配置文件只加载一次,然后在手动调用时刷新以刷新数据。 【参考方案1】:

由于您使用的是导航栏,您可能希望在 initState 函数中加载数据。一旦构建了导航栏,这将让您的数据加载。为了使用它,首先将您的无状态小部件转换为有状态小部件。它应该放在build () 上方。这是它的外观:

@override
  void initState() 
    // load your data here
    super.initState();
  

数据将加载一次,您可以将其放到导航栏项目中。我希望这会有所帮助!

【讨论】:

【参考方案2】:

我想通了,在我的 MaterialApp 调用的身份验证包装器中,我使用了带有嵌套 FutureBuilders 的 StreamBuilder 来解决我的问题。在此之后,我只是通过我的小部件树传递了变量。

我觉得好像有更好的方法可以做到这一点,但我还没有答案。所以我将使用它,因为它有效。

这是我的 _AuthWrapperState 类:

class _AuthWrapperState extends State<AuthenticationWrapper> 
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  Future<ProfileModel> _getProfile() async 
    return await Database(_firestore).getProfile(uid: _auth.currentUser.uid);
  

  Future<SharedPreferences> _getPrefs() async 
    return await SharedPreferences.getInstance();
  

  @override
  Widget build(BuildContext context) 
    return StreamBuilder(
      stream: AuthService(auth: _auth, firestore: _firestore).user,
      builder: (BuildContext context, AsyncSnapshot<User> snapshot) 
        if (snapshot.connectionState == ConnectionState.active) 
          if (snapshot.data?.uid == null) 
            return SignIn(auth: _auth, firestore: _firestore);
           else 
            return FutureBuilder(
                future: _getProfile(),
                builder: (builder, AsyncSnapshot<ProfileModel> snapshot) 
                  if (snapshot.hasData) 
                    ProfileModel profileModel = snapshot.data;
                    return FutureBuilder(
                        future: _getPrefs(),
                        builder: (context,
                            AsyncSnapshot<SharedPreferences> snapshot) 
                          if (snapshot.hasData) 
                            return Home(
                              auth: _auth,
                              firestore: _firestore,
                              profileModel: profileModel,
                              sharedPrefs: snapshot.data,
                            );
                           else 
                            return const Scaffold(
                              body: CircularProgressIndicator(),
                            );
                          
                        );
                   else 
                    return const Scaffold(
                        body: Center(child: CircularProgressIndicator()));
                  
                );
          
         else 
          return const Scaffold(
            body: Center(
              child: Text("Loading..."),
            ),
          );
        
      ,
    );
  

【讨论】:

以上是关于使用 Firestore 在 Flutter 中加载配置文件数据的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Firebase 托管的 Flutter web 无法从存储中加载图片

在 Flutter 中使用 Cloud Firestore 创建无限列表

使用 Flutter 将表单上传到 Firestore

如何使用 Firestore 在 Flutter 中搜索文本

Flutter 使用 Stream 检索 Firestore 集合

Firestore,Flutter,Async:方法不等待异步方法完成