I am trying to implement an auto-login feature. Basically on the startup, I want to check if any user data is saved at Flutter Secure Storage and then update my userProvider based on the result.
Here is the build method of the first screen
@override
Widget build(BuildContext context, WidgetRef ref) {
return FutureBuilder(
future: checkUser(),
builder: (context, snapshot) {
if(snapshot.hasData){
print("has data");
ref.read(userProvider.notifier).setUser(
snapshot.data!
);
}
else if(snapshot.hasError){
print(snapshot.error);
}
else{
return Container(
color: Colors.white,
child: const Center(
child: CircularProgressIndicator.adaptive(),
),
);
}
return AppBody(context);
},
);
}
And here is the provider I am trying to update
final userProvider = StateNotifierProvider<UserNotifier, User?>((ref) {
return UserNotifier();
});
It gives me this error:
Tried to modify a provider while the widget tree was building. If you are encountering this error, chances are you tried to modify a provider in a widget life-cycle, such as but not limited to:
Where can i update the provider value if I can not do it on the initializing?
Thank you for your time and answers.
You could try using a FutureProvider
to load the cached user data and consume the provider in the widget's build
method.
final userProvider = FutureProvider<User?>((ref) async {
final user = await ... // load user data from flutter secure storage
return user;
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final AsyncValue<User?> userAsync = ref.watch(userProvider);
return userAsync.when(
data: (user) {
if (user == null) {
return // login page;
} else {
return // home page;
}
},
loading: () => const Text('loading'),
error: (error, stack) => const Text('error'),
);
}
if you want to keep track of the user state, you could define a isLoggedInProvider
.
final isLoggedInProvider = Provider<bool>((ref) {
final user = ref.watch(userProvider).asData?.value;
return user != null;
});