StreamProvider не возвращает данных при использовании с Navigator

avatar
Martin
8 августа 2021 в 18:20
106
2
0

Проблема в том, что я не получаю никаких значений от своих StreamProviders (которые определены на глобальном уровне) в моем маршруте Authenticated:

  runApp(MultiProvider(
    providers: [
      Provider.value(value: userService),
      StreamProvider.value(value: authService.userStream, initialData: null),
      StreamProvider.value(value: userService.userDataStream),
      StreamProvider.value(value: userService.characterStream),
    ],
    child: MyApp(),
  ));
}

Я заметил, что это связано с логикой моего навигатора (если я его удаляю, значения поставщика передаются вниз по дереву виджетов, как и ожидалось). Навигатор, который я использую, основан на идее, что приложение имеет 3 состояния: Not Authenticated, Authenticated и Authenticated-First-Time. Я получаю значение, аутентифицирован ли я из loginStream (пока все работает):

@override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: loginStream,
      builder: (ctx, snapshot) {
        if (!snapshot.hasData) return Loading();
        LoginState state = snapshot.data;
        if (state == LoginState.LOGGED_OUT) return LoginScreen();
        if (state == LoginState.FIRST_TIME) return CharacterCreationScreen();
        return Navigator(
          key: navigatorKey,
          initialRoute: "/home",
          onGenerateRoute: (settings) => PageRouteBuilder(
            pageBuilder: (ctx, _, __) => routes(settings)(ctx),
            transitionsBuilder: pageTransition,
          ),
        );
      },
    );

Дело в том, что если я прошел аутентификацию и говорю на главном экране, то оба userDataStream и characterStream возвращают нуль, даже если доступны фактические данные. Если я удалю сам StreamBuilder + LoginLogic и просто верну виджет Navigator выше, то HomeScreen получит правильные значения.

ОБНОВЛЕНИЕ: Я заметил, что это даже не StreamBuilder. Если я удалю 3 if в построителе, тогда значения потока будут распространяться правильно. Не уверен, почему это происходит.

Источник

Ответы (2)

avatar
Mozes Ong
21 августа 2021 в 09:41
0

Изменить это

  Provider.value(value: userService),
  StreamProvider.value(value: authService.userStream, initialData: null),

К этому

Provider(create: (context) => userService)
StreamProvider(create:(context) => authService.userStream, initialData: null),

Проделайте то же самое для всех провайдеров, которых вы регистрируете

Чтобы представить вновь созданный объект, используйте конструктор поставщика по умолчанию. Не используйте конструктор .value, если вы хотите создать объект, иначе у вас могут возникнуть нежелательные побочные эффекты. https://pub.dev/packages/provider

Martin
22 августа 2021 в 13:34
0

Нет, это не помогает, к сожалению. Значения, которые я передаю, также уже инициализированы, что заставляет меня поверить, что .value в любом случае правильный путь. Хотя опять же, я пробовал, но не повезло

avatar
Jahn E.
17 августа 2021 в 19:58
0

Я не совсем уверен, поможет ли это, так как мне не хватает подробностей, но вот что я пока заметил:

  1. Если вы создаете объекты в мультипровайдере в первый раз, вам не следует использовать .value - проверьте, применимо ли это.
  2. Попробуйте очистить операторы if в теле функции вашего StreamBuilder (используйте ключевые слова if, else if и else.

Кроме того, следуя вашему описанию, звучит так, будто всякий раз, когда оператор if является истинным, возвращается и, таким образом, отменяет тело функции сборки, поток каким-то образом сбрасывается и по умолчанию принимает значение null. Возможно, изучите это и обновите свой вопрос.

Martin
22 августа 2021 в 13:37
0

Эй, .value должен быть правильным способом сделать это, так как я повторно использую уже начальные значения. Я пытался создать, но это тоже не работает. Очистка операторов if не работает :( И да, если оператор if верен, он каким-то образом сбрасывает поток (я не читаю поток из ветвей if)