问题描述
我有一个 firebase_providers.dart
文件,如下所示:
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:firebase_auth/firebase_auth.dart';
final firebaseAuthProvider = Provider((ref) => FirebaseAuth.instance);
final authStateChangesProvider = StreamProvider.autodispose<User?>((ref) {
return ref.watch(firebaseAuthProvider).authStateChanges();
});
它创建了 2 个简单的提供程序 - 一个用于 Firebase Auth 实例,另一个用于获取当前用户状态。我在我的主页上使用它,如下所示:
class NavigationManager extends HookWidget {
@override
Widget build(BuildContext context) {
final user = useProvider(authStateChangesProvider);
return user.when(
loading: () => CircularProgressIndicator(),error: (error,stack) => Text('Error occured'),data: (user) {
if (user == null) return LoginPage();
return Dashboard();
},);
}
}
LoginPage
是一个有状态的小部件,它包含文本字段、控制器等。在这个文件中,我在 userEmail
和 userPassword
中有用户电子邮件和密码,现在如何使用它登录一个用户? Firebase Auth 的官方文档使用以下代码:
UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: "barry.allen@example.com",password: "SuperSecretPassword!"
);
我也可以这样做,但不会涉及 Riverpod。我需要访问包含 firebaseAuthProvider
的 FirebaseAuth.instance
。要访问此提供程序,我需要在 HookWidget
内使用 useProvider
但这意味着将 ui 与逻辑混淆。我想在提供程序存在的同一个文件中将逻辑分开,即 firebase_providers.dart
我也想过做这样的事情 - 将 LoginPage
有状态小部件转换为 HookWidget,然后访问 firebaseAuthProvider
并使用它来调用可以驻留在 firebase_providers.dart
中的登录函数但是,我将如何管理我首先为其创建有状态小部件的表单和文本字段?
那么使用 Riverpod 管理和调用所有这些身份验证功能(例如登录、注册等)的方法是什么?
解决方法
标准方法是创建一个接受 ScopedReader
作为参数的服务类。
例如:
class AuthService {
const AuthService(this._read);
final Reader _read;
static final provider = Provider((ref) => AuthService(ref.read));
Future<void> emailSignIn(String email,String password) async {
final auth = _read(firebaseAuthProvider);
final credential = await auth.signInWithEmailAndPassword(email: email,password: password);
// etc.
}
}
然后在您的登录页面:
class LoginPage extends HookWidget {
const LoginPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async => context.read(AuthService.provider).emailSignIn(
'barry.allen@example.com','SuperSecretPassword!',),child: Text('Login'),);
}
}
同样的模式可以应用于使用 Firestore 或其他数据提供者的存储库类。