I'm coding on Login page with Riverpod, everything go fine but when user is try to login, system is stuck on loading state and didn't send data to data state. I don't know why.
my code is like this: login form -> login controller -> login repository, then send data back to login form and redirect to dashboard.
this code in login page
class LoginPage extends ConsumerWidget {
LoginPage({Key? key}) : super(key: key);
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.all(20),
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
padding: const EdgeInsets.all(20),
child: Column(
children: [
Image.asset(
"assets/images/logo.png",
width: 80,
),
const SizedBox(
height: 20,
),
TextField(
controller: usernameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Email / Username',
),
),
const SizedBox(
height: 20,
),
TextField(
controller: passwordController,
obscureText: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
),
const SizedBox(
height: 20,
),
TextButton(
onPressed: () {
final loginDataValue = ref.watch(loginControllerProvider({
"username": usernameController.text,
"password": passwordController.text
}));
loginDataValue.when(
data: (userData) {
if (userData["isLoggedIn"]) {
GoRouter.of(context).goNamed("home");
}
},
error: (e, __) => debugPrint(e.toString()),
loading: () => debugPrint("loading"));
},
child: const Text("Sign in"),
style: TextButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 105, 240, 233),
primary: Colors.black87,
minimumSize: const Size(88, 36),
padding: const EdgeInsets.symmetric(horizontal: 16.0)))
],
),
),
);
}
}
then, this is controller
import 'package:calendar/repositories/login_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class LoginController extends StateNotifier<AsyncValue<Map>> {
LoginController(this._loginRepository,
{required this.username, required this.password})
: super(const AsyncValue.loading()) {
login(username: username, password: password);
}
final LoginRepository _loginRepository;
final String username;
final String password;
Future<void> login(
{required String username, required String password}) async {
try {
state = const AsyncValue.loading();
final suggestions = await _loginRepository.loginUser(
username: username, password: password);
state = AsyncValue.data(suggestions);
} catch (err) {
state = AsyncValue.error(err);
}
}
}
final loginControllerProvider = StateNotifierProvider.autoDispose
.family<LoginController, AsyncValue<Map>, Map>((ref, data) {
final loginRepository = ref.watch(loginRepositoryProvider);
return LoginController(loginRepository,
username: data["username"], password: data["password"]);
});
then, this is repository
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class LoginRepository {
Future<Map> loginUser(
{required String username, required String password}) async {
try {
return {
"username": username,
"token": "tokenfromapi",
"isLoggedIn": true
};
} catch (err) {
throw AsyncValue.error(err);
}
}
}
final loginRepositoryProvider = Provider<LoginRepository>((ref) {
return LoginRepository();
});
can anyone tell me, what is wrong?
thank you
Looks overly complicated, I would simplify a lot. Something like this:
final loginControllerProvider = FutureProvider.family<Map, Map>((ref, data) async {
//TODO call login API
return {
"username": data["username"],
"token": "tokenfromapi",
"isLoggedIn": true
};
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.