Флаттер с использованием StreamBuilder с обновлениями setState

#firebase #flutter #google-cloud-firestore #stream-builder

#firebase #flutter #google-облако-firestore #stream-builder

Вопрос:

Я использую StreamBuilder внутри метода сборки для извлечения информации о пользователе из firestore и сразу после ее отображения в Listview.builder.

Как только я получу информацию о пользователе, я вызываю другой API с идентификатором пользователя, чтобы получить некоторую другую информацию, которую я хотел бы отобразить в списке. Это дает мне будущее для каждого пользователя, как только будущее будет «выполнено» (внутри Future.then()), затем я сохраняю данные и вызываю setState(); чтобы перестроить список с новыми данными.

Проблема в том, что после вызова setState() метод сборки перезапускается, что снова возвращает мне пользователей, и это вызывает бесконечный цикл извлечения пользователей и данных из второго API.

Это похоже на типичный сценарий, но я не знаю, как решить это с помощью StreamBuilder. Мое предыдущее решение извлекало пользователей из initState, поэтому оно не вызывалось бесконечно. Какие-либо советы?

«getotherapeidata» перебирает извлеченных пользователей и добавляет данные «расстояние» в список, и список сортируется на основе пользователя с наибольшим / наименьшим расстоянием. Код:

 @override
Widget build(BuildContext context) {

return Scaffold(
  body: StreamBuilder<List<IsFriend>>(
    stream: viewModel.isFriendStream(),
    builder: (_, snapshot) {
      if (snapshot.connectionState == ConnectionState.active) {
        List<IsFriend> friends = snapshot.data;
        if (friends == null || friends.isEmpty) {
          return Scaffold(
              body: Center(
                child: Text("Friend list is empty :("),
              )
          );
        } else {
          userList = friends;
          getOtherAPIData();
          return getListview(userList);
        }
      }
      return Scaffold(
          body: Center(
            child: CircularProgressIndicator(),
          )
      );
    }
  ),

..
..
void getOtherAPIData() async {
for (IsFriend friend  in userList) {
  await fitbitServ.getData(friend.user.uid).then((fitData) {
    setState(() {
      setDistanceOnUser(fitData.distanceKm, friend.user.uid);
      totalDistance  = fitData.distanceKm;
      sortUsers(userDataList);
      userData[friend.user.uid] = fitData;
    });
  });
}
  

}

Ответ №1:

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

  1. Начните загрузку данных в конструктор виджета.
  2. Вызывайте setState , когда данные будут доступны.
  3. Визуализируйте данные из состояния в build .

Комментарии:

1. Итак, решение состоит в том, чтобы не использовать StreamBuilder в подобных случаях? Я не понимаю, как я мог бы использовать ваш подход в этом сценарии, поскольку извлечение моих данных зависит от данных из StreamBuilder (которые, конечно, находятся внутри build() )

2. Использование a StreamBuilder тоже прекрасно, но затем вы не можете начать загрузку данных, которые он отображает в своем собственном builder теле. Вложенные компоновщики — это нормально, но как только компоновщик запускает загрузку собственных данных в свой builder метод, вы запускаете цикл, как вы видите.