Как правильно сделать панель поиска во Flutter без лишних звонков в Cloud Firestore? - PullRequest
0 голосов
/ 06 апреля 2020

Я пытаюсь добавить панель поиска в свое приложение Flutter. Моя цель - использовать его для фильтрации списка элементов в ListView. Я использую Cloud Firestore для части базы данных, и я хочу использовать ее возможность обновлять список данных в режиме реального времени с помощью его системы моментальных снимков.

Вот что у меня есть сейчас. Я попытался сделать его максимально простым, поэтому извините, если код уродлив:

  // This controller handles the search string.
  final TextEditingController _filter = new TextEditingController();

  ListView _listView;

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

    // The widget is rebuilt every time the search string changes.
    // I tried to use _listView.build(context) instead but it does not work.
    _filter.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: _buildStream(_user),
        builder: (context, snapshot) {  

          // Filter the snapshot documents.
          var itemList = new List<MyItem>();
          var allDocuments = snapshot.data.documents;
          for (var i = 0; i < allDocuments.length; i++) {
            var documentSnapshot = allDocuments[i];
            MyItem item = MyItem.fromSnapshot(documentSnapshot);
            if (item.name.contains(_filter.text)) itemList.add(item);
          }

          _listView = ListView.builder(
            itemCount: itemList.length,
            itemBuilder: (context, i) =>
                _buildListItem(context, itemList[i], i),
          );
          return _listView;
        });
  }

  Stream<QuerySnapshot> _buildStream(User user) {
    return Firestore.instance
        .collection('items')
        .where('testId', isEqualTo: user.ID)
        .snapshots();
  }

По сути, я делаю фильтрующую часть в конструкторе StreamBuilder. Этот код дает мне желаемый результат, но меня беспокоит тот факт, что он будет вызывать Firestore каждый раз, когда письмо добавляется или удаляется в строке поиска. Это не является оптимальным с точки зрения производительности, и, как я понимаю, Firestore будет выставлять мне счета каждый раз, когда пользователь изменяет строку поиска, даже если одни и те же элементы возвращаются снова и снова. Я знаю, что обычно снимки Firestore могут обновляться в режиме реального времени, и вы платите только за различия с предыдущим снимком, но я не думаю, что это работает в этом случае, потому что весь виджет перестраивается каждый раз, когда кто-то изменяет строку поиска.

Очевидно, что выполнять фильтрацию в _buildStream было бы чище, но у меня все еще будет та же проблема с биллингом. Выполнение этого в компоновщике, кажется, является единственным вариантом.

Я не могу найти способ предотвратить перестройку всего виджета и избежать этих ненужных вызовов. Есть ли способ сделать это?

1 Ответ

0 голосов
/ 08 апреля 2020

Я закончил создание потока во время инициализации виджета.

  // This controller handles the search string.
  final TextEditingController _filter = new TextEditingController();

  ListView _listView;
  Stream<QuerySnapshot> _stream; // <-------------------- ADDED THIS

  @override
  void initState() {
    super.initState();
    _stream = _buildStream(_user); // <-------------------- ADDED THIS

    // The widget is rebuilt every time the search string changes.
    // I tried to use _listView.build(context) instead but it does not work.
    _filter.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: _stream, // <-------------------- CHANGED THIS
        builder: (context, snapshot) {  

          // Filter the snapshot documents.
          var itemList = new List<MyItem>();
          var allDocuments = snapshot.data.documents;
          for (var i = 0; i < allDocuments.length; i++) {
            var documentSnapshot = allDocuments[i];
            MyItem item = MyItem.fromSnapshot(documentSnapshot);
            if (item.name.contains(_filter.text)) itemList.add(item);
          }

          _listView = ListView.builder(
            itemCount: itemList.length,
            itemBuilder: (context, i) =>
                _buildListItem(context, itemList[i], i),
          );
          return _listView;
        });
  }

  Stream<QuerySnapshot> _buildStream(User user) {
    return Firestore.instance
        .collection('items')
        .where('testId', isEqualTo: user.ID)
        .snapshots();
  }

У меня все еще есть обновление в реальном времени в моем списке данных, но без ненужных вызовов Firestore.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...