Является ли вложенный StreamBuilder хорошим шаблоном? - PullRequest
0 голосов
/ 06 мая 2019

Я загружаю статьи из HackerNews API, используя Bloc Pattern и Streams.

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

Теперь я завернул статью, загружающую Stream Builder, с новой загрузкой StreamBuilder. Теперь, когда у построителя потока загрузки установлено значение true (означает, что он загружается), он отображает круговой индикатор прогресса или, в противном случае, показывает дочерний элемент (список статей, обернутый в Stream Builder).

Это отлично работает. Но меня беспокоит, что я завернул Stream Builder внутри Stream Builder. Я знаю, что могу воспользоваться помощью rxdart, но я просто не знаю, как.

Я пытался добавить загрузчик с помощью snapshot.hasData или нет, но это не сработало, поэтому я решил создать другой поток и тему, которая принимает bool и сообщает пользовательскому интерфейсу, загружается он или нет.

Код, извлекающий данные из блока:

 _getAndUpdateArticles(StoryType storyType) {
    _isLoadingSubject.add(true);
    getListIds(storyType).then((list) {
      getArticles(list.sublist(0, 10)).then((_){
        _articleSubject.add(UnmodifiableListView(_articles));
        _isLoadingSubject.add(false);
      });
    });
  }

UI:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: StreamBuilder(
        stream: widget.hnBloc.isLoading,
        builder: (context, snapshot) {
          if (snapshot.data) {
            return Center(child: CircularProgressIndicator());
          } else {
            return StreamBuilder<UnmodifiableListView<Article>> (
              initialData: UnmodifiableListView<Article>([]),
              stream: widget.hnBloc.article,
              builder: (context, snapshot) => ListView(
                children: snapshot.data.map(_buildItem).toList(),
              ),
            );
          }
        },
      ),
  .........

EDIT

Я пробовал это, но это не работает:

StreamBuilder<UnmodifiableListView<Article>> (
        initialData: UnmodifiableListView<Article>([]),
        stream: widget.hnBloc.article,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView(
              children: snapshot.data.map(_buildItem).toList(),
            );
          } else {
            return CircularProgressIndicator();
          }
        }
      ),

1 Ответ

1 голос
/ 07 мая 2019

Не думаю, что есть полный способ избежать вложенных StreamBuilders. Я лично не считаю это плохой практикой, но это определенно приведет к большему количеству сборки.
В вашем случае вы можете изменить ваш hnBloc так, чтобы он выдавал одно состояние, которое может быть состоянием загрузки или состоянием данных, тем самым устраняя необходимость во вложенном StreamBuider.

например.

StreamBuilder<HnState>(
          stream: hnBloc.currentState,
          initialData: HnLoadingState(),
          builder: (context, snapshot) {
            if (snapshot.data is HnLoadingState) {
              return Center(child: CircularProgressIndicator());
            }if (snapshot.data is HnDataState) {
              return ListView(
                children: snapshot.data.map(_buildItem).toList(),
              ),
            }

          },
)  

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

...