Размещение двух экземпляров Firestore.instate внутри initState () - PullRequest
0 голосов
/ 30 мая 2020

Теперь это может быть хорошая практика или полное отрицание !!

Я пытался сопротивляться размещению большего количества StreamBuilder (s) под build(BuildContext context) и пытался использовать вместо initState(). У меня проблемы из-за неправильного использования Future / async / await. String _leaseTenantName (первый initState() Firestore.instance) будет иметь правильное значение, но строки _leaseUnitName & _leaseUnitPropertyUid (второй initState() Firestore.instance) обычно возвращаются как null. При сборке StreamBuilder<PropertyDetails> ниже будет выдано сообщение об ошибке 'Invalid document reference. Document references must have an even number of segments, but properties has 1, null)', но попытки продолжаются и в конечном итоге сработали, когда _leaseUnitPropertyUid, наконец, получил значение.

Я считаю, что решение состоит в том, чтобы каким-то образом обернуть два initState() Firestore.instances в Future / async / await, но не смог найти способ сделать это. Любые идеи?? Или мне просто использовать еще больше вложенных StreamBuilder s?

class _LeaseTileState extends State<LeaseTile> {
  String _leaseTenantName = '';
  String _leaseUnitPropertyUid = '';
  String _leaseUnitName = '';
  String _leasePropertyName = '';
  String _leasePropertyUnitName = '';

  @override
  void initState() {
    super.initState();
    Firestore.instance
        .collection("companies")
        .document(widget.leaseDetails.tenantUid)
        .snapshots()
        .listen((snapshot) {
      _leaseTenantName = snapshot.data['companyName'];
    });

    Firestore.instance
        .collection("units")
        .document(widget.leaseDetails.unitUid)
        .snapshots()
        .listen((snapshot) {
      _leaseUnitName = snapshot.data['unitName'];
      _leaseUnitPropertyUid = snapshot.data['propertyUid'];
    });
  }

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);
    return StreamBuilder<PropertyDetails>(
        stream: DatabaseServices(propertyUid: _leaseUnitPropertyUid)
            .propertyByDocumentID,
        builder: (context, userCompany) {
          if (!userCompany.hasData) return Loading();
          _leasePropertyName = userCompany.data.propertyName;
          _leasePropertyUnitName = '$_leasePropertyName - $_leaseUnitName';
          return Card(

1 Ответ

2 голосов
/ 02 июня 2020

Это большой нет.

Во-первых, нет ничего плохого в использовании нескольких StreamBuilder, StreamBuilder, которые помогут вам упростить использование Streams, чтобы вы не испортили вещи их подписки ... как вы делали в initState().

Когда вы звоните listen() на snapshots(), как вы делали на initState(), вы создали подписку, эта подписка должна быть отменена dispose(), но вы не отменяете его, так что у вас происходит утечка памяти, StreamBuilder спасет вас здесь, поскольку он управляет этим за вас.

Еще одна вещь, о которой следует помнить, - это то, что вы используете _leaseUnitPropertyUid на build(), но вы не проверяете, действительно ли _leaseUnitPropertyUid. _leaseUnitPropertyUid будет установлен только после того, как Firebase snapshot() Stream испускает одно значение, а build() может быть вызван до этого. Опять же, StreamBuilder спас бы вас здесь, так же как вы могли бы проверить, выдало ли оно значение или нет.

Также вы жестко кодируете Firebase.instance в своем коде, что очень затрудняет тестирование . Взгляните на Dependency Injection и попробуйте внедрить Firebase.instance в свой класс, например, шаблон репозитория или что-то подобное, чтобы вы могли заменить Firebase.instace на тестирование Mock и сделайте ваш код более тестируемым.

...