Флаттер: как работать с StreamProvider, FireStore и Drawer - PullRequest
0 голосов
/ 12 апреля 2020

У меня проблема с использованием 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 для предоставления user.userUid из StreamProvider в другие StreamProviders ниже этого, но не могли заставить что-либо работать.

Далее в 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 (ов), и все работает. Provider.of в Home () и HomePage () (вызываемые Home ()) предоставили вкусности.

Теперь у Home () есть Drawer:

 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 доступен внутри самого ящика, но любой виджет, вызываемый из ящика, выдает ошибку, что он не может найти соответствующий StreamProvider для провайдера. Если я опровергаю соответствующий StreamProvider обратно в MyAPP (), соответствующий StreamProvider может быть найден. Но без значений из Firestore, если я не выдумал и для user.userUid жестко закодировал действительный uid :. Очевидно, что это не решение, но оно работает в отношении виджетов, вызываемых Drawer.

Я ищу, чтобы понять, как использовать ProxyProvider или, если это не решение, как структурировать мой код. Может быть, я могу использовать StreamProviders (или StreamBuilders) в каждом виджете, вызываемом из Drawer, но это не так. Код: https://github.com/sctajc/property_returns.

1 Ответ

1 голос
/ 15 апреля 2020

На сегодняшний день ProxyProvider не работает как StreamProvider, поэтому вы не можете использовать его так, как вам хочется.

Чтобы ответить, почему ваш Drawer имеет доступ к Provider.of<Foo>, когда маршруты открываются из это не потому, что routes определены в вашем MaterialApp.

Что это значит? Это означает, что хотя Drawer ниже Wrapper и, следовательно, имеет доступ к Provider.of<Foo>, другие маршруты технически выше виджета Wrapper.

TL: DR

Решением было бы просто создать один ProxyProvider вашего DatabaseServices следующим образом:

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

И затем, если вам нужно подключиться к UserData, вам просто нужно сделать:

Provider.of<DatabaseServices>(context).userData

Таким образом вы избегаете создания 4 экземпляров одного и того же объекта (DatabaseServices) и одновременно решаете свою проблему. Тем не менее, логика c вашего приложения должна будет немного измениться, чтобы оно заработало, я уверен, что это не будет проблемой.

Я надеюсь, что это может помочь вам, и вы можете продолжать разработку ваше приложение!

...