Reputation: 1355
I'm trying to use riverpod to store the user info stored in Firestore upon logging in. The two pieces of info I want to store is the user's mobile number and which account is he subscribed to. If the these fields are null, then the user will be show a QR reader that should read this info and store it Firestore and also update riverpod locally
My user loading page is as follows:
I'm getting the error setState() or markNeedsBuild() called during build.
.
Why is that?
I think it's because the code is updating the build method at the same it's still building.
But my understanding of the docs is that context.read() shouldn't be rebuilding the widget.
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),
);
}
}
},
);
}
}
In the QR page, riverpod values are null, although the firestore values are not null. So the values are not being stored in riverpod properly in the previous page. Which I think it's because of the exception in the loading page.
My build method inside the QR page is as follows:
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],
},
);
},
);
}
My providers:
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();
}
}
Upvotes: 0
Views: 725
Reputation: 599
You can read a state in the build method but can't change it because the root ProviderScope is listening to it. And this cause the error you have.
To correct it you should create a firebase instance provider and use dependencies between providers to update the state when your user/firebase instance has finished loading.
Upvotes: 0