Нежелательные перестройки виджета 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 завершил загрузку.