Flutter:如何处理使用 StreamProvider、FireStore 和使用 Drawer

Posted

技术标签:

【中文标题】Flutter:如何处理使用 StreamProvider、FireStore 和使用 Drawer【英文标题】:Flutter: How to handle using StreamProvider, FireStore and using Drawer 【发布时间】:2020-07-24 17:50:43 【问题描述】:

我在使用“StreamProvider”和让“Provider.of”交付商品时遇到问题。我有两个相互关联的问题。 (1)我无法让 ProxyProvider 工作(很可能我只是误解了它,它可能不是解决方案)。 (2) 小部件 Drawer()(或我使用它的方式)似乎阻止了“Provider.of”。在树上找不到“StreamProvider”。

在 MyApp() 中我最初有:

return MultiProvider(
      providers: [
        StreamProvider<User>.value(value: AuthService().user),
        StreamProvider<UserData>.value(
            value: DatabaseServices(uid: 'user.userUid').userData),
        StreamProvider<QuerySnapshot>.value(
            value: DatabaseServices(uid: 'user.userUid').allTasks),
        StreamProvider<List<TaskDetails>>.value(
            value: DatabaseServices(uid: 'user.userUid').userTasksByImportance),
        StreamProvider<List<PropertyDetails>>.value(
            value: DatabaseServices(uid: 'UuO2DO0JUVbVD0R1JqIclI7fprF3')
                .userProperties),
      ],
      child: MaterialApp(
        theme: themeData,
        home: Wrapper(),
        routes: 
          SettingsForm.id: (context) => SettingsForm(),
          TaskList.id: (context) => TaskList(),
          AddTask.id: (context) => AddTask(),
          EditTask.id: (context) => EditTask(),
          PropertyList.id: (context) => PropertyList(),
          AddProperty.id: (context) => AddProperty(),
          AddUnit.id: (context) => AddUnit(),
          TestMarkdown.id: (context) => TestMarkdown(),
        ,
      ),
    );

我尝试使用 ProxyProvider 将来自 StreamProvider 的 user.userUid 提供给它下面的其他 StreamProvider,但无法正常工作。

接下来在 Wrapper() 我尝试了这个:

class Wrapper extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    final user = Provider.of<User>(context);
    if (user == null) 
      return Authenticate();
     else 
      return MultiProvider(
        providers: [
          StreamProvider<UserData>.value(
              value: DatabaseServices(uid: user.userUid).userData),
          StreamProvider<List<TaskDetails>>.value(
              value: DatabaseServices(uid: user.userUid).userTasksByImportance),
          StreamProvider<QuerySnapshot>.value(
              value: DatabaseServices(uid: user.userUid).allTasks),
          StreamProvider<List<PropertyDetails>>.value(
              value: DatabaseServices(uid: user.userUid).userProperties),
        ],
        child: Home(),
      );
    
  

现在这在 MaterialApp() 之下,我认为这不是一个好主意,但我可以让 user.user.Uid 可用于其他 StreamProvider(s) 并且一切正常。 Home() 和 HomePage() 中的 Provider.of(由 Home() 调用)提供了这些好东西。

现在 Home() 有一个抽屉:

 return Scaffold(
        drawer: buildDrawer(context),
        backgroundColor: Colors.blueAccent[50],
        appBar: appBar,
        body: Container(
          padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
          decoration: BoxDecoration(
            color: Colors.white,
            image: DecorationImage(
                alignment: Alignment.bottomCenter,
                image: AssetImage('assets/property_returns_logo_drawn.png'),
                fit: BoxFit.fitWidth),
          ),
          child: HomePage(),
        ),
      );
    
  

  Drawer buildDrawer(BuildContext context) 
    final user = Provider.of<User>(context);
    final userData = Provider.of<UserData>(context);
    final userProperties = Provider.of<List<PropertyDetails>>(context);
    final double _minHeight = 40;
    final double _maxHeight = 40;

    return Drawer(
      child: ListView(
        padding: EdgeInsets.all(0),
        children: <Widget>[
          DrawerHeader(

并且 userProperties 在抽屉本身中是可用的,但是从抽屉中调用的任何小部件都会给出错误,即它找不到 Provider.of 的相关 StreamProvider。如果我在 MyAPP() 中返回相关的 StreamProvider,则可以找到相关的 StreamProvider。但是没有来自 Firestore 的值,除非我捏造并且为 user.userUid 硬编码一个有效的 uid:。显然不是一个解决方案,但就 Drawer 调用的小部件而言,它可以工作。

我正在寻找的是了解如何使用 ProxyProvider,或者如果这不是解决方案,如何构建我的代码。也许我可以在从 Drawer 调用的每个小部件中使用 StreamProviders(或 StreamBuilders),但这感觉不对。代码在https://github.com/sctajc/property_returns。

【问题讨论】:

【参考方案1】:

截至今天,ProxyProvider 不再作为 StreamProvider 工作,因此您无法按照自己的方式使用它。

要回答为什么您的Drawer 可以访问Provider.of&lt;Foo&gt; 而从它打开的路由却没有,是因为routes 是在您的MaterialApp 中定义的。

这是什么意思?这意味着虽然Drawer 低于Wrapper,因此可以访问Provider.of&lt;Foo&gt;,但从技术上讲,其他路由高于Wrapper 小部件。

TL:DR

解决方案就是像这样创建一个ProxyProviderDatabaseServices

ProxyProvider<User, DatabaseServices>(
    update: (_, user, __) => DatabaseServices(uid: user?.userUid),
),

然后,如果您需要利用 UserData,您只需:

Provider.of<DatabaseServices>(context).userData

这样可以避免创建同一个对象 (DatabaseServices) 的 4 个实例,同时可以解决问题。但是,您的应用程序的逻辑需要稍作更改才能使其正常运行,我相信这不会有问题。

我希望这可以帮助你,你可以继续开发你的应用程序!

【讨论】:

谢谢弗朗西斯科。这当然帮助我理解了这个问题,并且我已经按照你的建议进行了代码更改。像 Provider.of(context).userProperties;'我可以 print() 出有一个实例。我现在正在努力解决的是访问 userProperties 中的数据。我原以为这与之前的方法类似('userProperty.propertyName' 或 'userProperty[i].userName'(如果在列表中)),但是有什么提示可以尝试吗? 例如,您可以使用一些 StreamBuilders 来读取数据。我知道这可能需要做更多的工作,但另一种选择是创建您自己的 StreamProxyProvider ......我知道到目前为止您所做的工作更多,但没有太多其他选择! 谢谢弗朗西斯科。现在我明白了我可以向前推进的问题

以上是关于Flutter:如何处理使用 StreamProvider、FireStore 和使用 Drawer的主要内容,如果未能解决你的问题,请参考以下文章

firebase、flutter应该如何处理好友请求和邀请? [关闭]

我应该如何处理:Wordpress 社交登录(网络)和 Flutter(移动)

Flutter 如何处理 Stream 和 Future 返回错误

Flutter Provider select - 如何处理复杂的返回类型,如 List 或 Map

Flutter 如何处理异步/等待中的错误

Flutter如何处理框内固定大小的图像?