Нежелательные перестройки виджета Riverpod (я думаю)

Я пытаюсь использовать riverpod для хранения информации о пользователе, хранящейся в Firestore при входе в систему. Две части информации, которую я хочу сохранить, - это номер мобильного телефона пользователя и учетная запись, на которую он подписан. Если эти поля равны нулю, то пользователю будет показан QR-ридер, который должен прочитать эту информацию и сохранить ее в Firestore, а также обновить riverpod локально.

Моя страница загрузки пользователя выглядит следующим образом: Я получаю сообщение об ошибке setState() or markNeedsBuild() called during build.. Это почему? Я думаю, это потому, что код обновляет метод сборки так же, как он все еще строит. Но мое понимание документации таково, что context.read() не должен перестраивать виджет.

      final subscribedToProvider = ChangeNotifierProvider((_) => SubscribedTo());
final userMobileProvider = ChangeNotifierProvider((_) => UserMobileProvider());

class LandingRouting extends StatelessWidget {
  const LandingRouting({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    User user = context.watch<User>();

    if (user == null) return LoginScreen();

    return FutureBuilder(
      future: FirebaseFirestore.instance.collection('users').doc(user.uid).get(),
      builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) return Loading();

        if (snapshot.hasError)
          return AlertDialog(
            title: Text('Error loading user'),
            content: Text('${snapshot.error.toString}'),
          );
        else {
          Map<String, dynamic> userData = snapshot.data.data();

          if (userData['userType'] == 'baqala') {
            return Theme(data: baqalaTheme, child: const BaqalaHomeScreen());
          } else {
            String subscribedTo = userData['subscribedTo'];
            String mobile = userData['mobile'];

            context.read(userMobileProvider).update(mobile);  // <--
            context.read(subscribedToProvider).update(subscribedTo); // <--

            return Theme(
              data: userTheme,
              child: UserHomeScreen(subscribedTo: subscribedTo, userMobile: mobile),
            );
          }
        }
      },
    );
  }
}

На странице QR значения riverpod равны нулю, хотя значения firestore не равны нулю. Значит, значения на предыдущей странице не сохраняются в Riverpod должным образом. Я думаю, это из-за исключения на странице загрузки.

Мой метод сборки внутри QR-страницы выглядит следующим образом:

      final subscribedToProvider = ChangeNotifierProvider((ref) => SubscribedTo());
final userMobileProvider = ChangeNotifierProvider((ref) => UserMobileProvider());

....

  @override
  Widget build(BuildContext context) {

    return Consumer(
      builder: (context, watch, child) {
        String sub = watch(subscribedToProvider).subscribedTo;
        String mob = watch(userMobileProvider).mobile;
        if (sub == null || mob == null) {
          return Column(
            children: [
              Expanded(
                flex: 3,
                child: QRView(key: qrKey, onQRViewCreated: _onQRViewCreated),
              ),
              Expanded(
                flex: 1,
                child: Center(
                  child: (result != null)
                      ? Text('Barcode Type: ${describeEnum(result.format)}   Data: ${result.code}')
                      : Text(
                          // 'Scan your code at your baqala to get your hisab history',
                          'Go to your baqala and request your QR code.\n'
                          'If your baqala has added you as a subscriber, you will be able to see\n'
                          'your account history\n\n',
                          style: TextStyle(fontSize: 18),
                          textAlign: TextAlign.center,
                        ),
                ),
              ),
            ],
          );
        }

        return History2(baqalaUID: sub, mobile: mob);
      },
    );

  }

  void _onQRViewCreated(QRViewController controller) {
    this.controller = controller;
    controller.scannedDataStream.listen(
      (scanData) async {
        setState(() => result = scanData);
        List<String> qrcode = scanData.code.split('-');

        context.read(subscribedToProvider).update(qrcode[0]);  // <-- Am I updating correctly
        context.read(userMobileProvider).update(qrcode[1]);

        await FirebaseFirestore.instance.collection('users').doc(CurrentUser.getCurrentUser().uid).update(
          {
            'subscribedTo': qrcode[0],
            'mobile': qrcode[1],
          },
        );
      },
    );
  }

Мои провайдеры:

      class SubscribedTo extends ChangeNotifier {
  String _subscribedTo;
  String get subscribedTo => _subscribedTo;

  void update(String subscribedTo) {
    _subscribedTo = subscribedTo;
    notifyListeners();
  }
}

class UserMobileProvider extends ChangeNotifier {
  String _mobile;
  String get mobile => _mobile;

  void update(String mobile) {
    _mobile = mobile;
    notifyListeners();
  }
}

1 ответ

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

Чтобы исправить это, вы должны создать поставщика экземпляра firebase и использовать зависимости между поставщиками для обновления состояния, когда ваш экземпляр пользователя /firebase завершил загрузку.

Другие вопросы по тегам