Currently I am facing a problem, I am using AsyncNotifier for my login page and there I am saving token in Auth provider and user information in User provider, but when I try to retrieve user data in profile screen it shows null, it seems state not persist between screens ... What am I doing wrong?
My User provider:
@Riverpod(keepAlive: true)
class User extends _$User {
@override
Future<UserModel?> build() async => null;
Future<void> setUser(UserModel user) async {
state = AsyncData(user);
}
void signOut() {
state = const AsyncData(null);
}
}
My Auth provider:
@riverpod
class Auth extends _$Auth {
@override
Future<AuthModel?> build() async => null;
Future<void> login(String username, String password) async {
var dio = getDio();
var response = await dio.post(
'/login',
data: {
'username': username,
'password': password,
},
);
state = AsyncData(AuthModel.fromJson(response.data));
ref
.read(userProvider.notifier)
.setUser(UserModel.fromJson(response.data['user']));
}
}
User profile screen:
class ProfileScreen extends ConsumerWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
var user = ref.watch(userProvider);
return Column(
children: [
Text("${user.value?.fullName}"), // null
Text("${user.value?.login}") // null
]
);
}
}
Login page:
class LoginScreen extends ConsumerStatefulWidget {
const LoginScreen({super.key});
@override
ConsumerState<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends ConsumerState<LoginScreen> {
final TextEditingController login = TextEditingController();
final TextEditingController password = TextEditingController();
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: login,
),
TextField(
controller: password,
),
ElevatedButton(
onPressed: () {
ref
.read(authProvider.notifier)
.login(
login.text,
password.text,
)
.then(
(_) => Navigator.pushNamed(context, "profile"),
);
},
child: Text("Login")),
],
);
}
}
It was because I tried to manipulate userProvider
before it was initialized.
I fixed this by adding ref.watch(userProvider)
in LoginScreen
.
You may have a question:
It will rebuild this screen for every change, isn't this a bad practice ?
Answer:
Since changes in providers like auth and user usually affect your entire app you probably want to trigger a rebuild anyway. Therefore, I watch them at the top of the widget tree.