如何在 Flutter (Dart) 中使用新路线获取儿童的 StreamProvider 数据
How to get StreamProvider data in children with new routes in Flutter (Dart)
我正在使用 StreamProvider 方法用某些数据包装我的小部件,例如来自 Firebase Auth 的 Auth(它在我的应用程序中的任何地方都有效)。我想对 Firestore 值做同样的事情,但它似乎只在一层深度起作用。
我有一个数据库调用,可以在完成身份验证检查后查找员工资料。当我尝试使用 Provider.of(context) 从我的 Home() 小部件中获取员工时,效果很好:
这是我的包装小部件(这是我的主文件的主页:小部件)
class Wrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user.uid);
// Return either home or authenticate widget
if (user == null) {
return Authenticate();
}
else {
return StreamProvider<Employee>.value(
value: DatabaseService().linkedEmployee(user.uid),
child: Home(),
);
}
}
}
DatabaseService() 中的数据库服务函数:
// Get Linked Employee
Stream<Employee> linkedEmployee(String uid) {
return employeesCollection.where("linkedUser", isEqualTo: uid).snapshots().map(_linkedEmployeeFromSnapShot);
}
Employee _linkedEmployeeFromSnapShot(QuerySnapshot snapshot) {
final doc = snapshot.documents[0];
return Employee(
eId: doc.data["eId"],
employeeCode: doc.data["employeeCode"],
fName: doc.data["fName"],
lName: doc.data["lName"],
docId: doc.documentID
);
}
我可以从树中任意位置的任何小部件访问 Provider.of<User>(context)
。那么为什么我不能对 Provider.of<Employee>(context)
做同样的事情呢?
当我在 Home() 以外的任何小部件中尝试这样做时,我收到错误消息:
错误:无法在此车辆小部件上方找到正确的提供商
例如,在我的小部件 Vehicles 中:
class Vehicles extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
final employee = Provider.of<Employee>(context);
...
User Provider 工作正常,我可以打印出来,但是 employee provider 不工作。
跟语境有关吗?谢谢,如有任何建议,我们将不胜感激。
我如何使用此事件的凸起按钮从 Home() 导航到 Vehicles() 小部件:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Vehicles())
);
},
这里有一个解释更详细的回复,因此我认为有些人会遇到这个问题,而且我也认为要解决这个问题有点棘手,尤其是当您的 Firestore 中有规则要求用户获得访问权限时数据库。
但通常,您希望围绕 MaterialApp()
.
包装提供程序(您希望访问所有应用程序)
所以我将向您展示一个简单的示例,以便于您理解它。
//The App() handles makes the providers globally accessible
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FirebaseAuthProviderLayer(
child: AuthorizedProviderLayer(
authorizedChild: MatApp(child: StartSwitch()),
unAuthorizedChild: MatApp(child: SignInScreen()),
),
);
}
}
//The MaterialApp Wrapped so that it not has to be rewritten
class MatApp extends StatelessWidget {
Widget child;
MatApp({this.child});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App',
home: child,
);
}
}
class FirebaseAuthProviderLayer extends StatelessWidget {
final Widget child;
FirebaseAuthProviderLayer({this.child});
@override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: FirebaseAuth.instance.authStateChanges(),
child: child,
);
}
}
//And the layer that decides either or not we should attach all the providers that requires the user to be authorized.
class AuthorizedProviderLayer extends StatelessWidget {
Widget authorizedChild;
Widget unAuthorizedChild;
AuthorizedProviderLayer({this.unAuthorizedChild, this.authorizedChild});
User user;
final FirestoreService firestoreService =
FirestoreService(); //The Service made to access Firestore
@override
Widget build(BuildContext context) {
user = Provider.of<User>(context);
if (user is User)
return MultiProvider(
providers: [
StreamProvider<FirestoreUserData>.value(
value: firestoreService.streamUser(),
),
StreamProvider<AppSettings>.value(
value: firestoreService.streamSettings(),
initialData: null,
)
],
child: authorizedChild,
);
return unAuthorizedChild;
}
}
我正在使用 StreamProvider 方法用某些数据包装我的小部件,例如来自 Firebase Auth 的 Auth(它在我的应用程序中的任何地方都有效)。我想对 Firestore 值做同样的事情,但它似乎只在一层深度起作用。
我有一个数据库调用,可以在完成身份验证检查后查找员工资料。当我尝试使用 Provider.of(context) 从我的 Home() 小部件中获取员工时,效果很好:
这是我的包装小部件(这是我的主文件的主页:小部件)
class Wrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user.uid);
// Return either home or authenticate widget
if (user == null) {
return Authenticate();
}
else {
return StreamProvider<Employee>.value(
value: DatabaseService().linkedEmployee(user.uid),
child: Home(),
);
}
}
}
DatabaseService() 中的数据库服务函数:
// Get Linked Employee
Stream<Employee> linkedEmployee(String uid) {
return employeesCollection.where("linkedUser", isEqualTo: uid).snapshots().map(_linkedEmployeeFromSnapShot);
}
Employee _linkedEmployeeFromSnapShot(QuerySnapshot snapshot) {
final doc = snapshot.documents[0];
return Employee(
eId: doc.data["eId"],
employeeCode: doc.data["employeeCode"],
fName: doc.data["fName"],
lName: doc.data["lName"],
docId: doc.documentID
);
}
我可以从树中任意位置的任何小部件访问 Provider.of<User>(context)
。那么为什么我不能对 Provider.of<Employee>(context)
做同样的事情呢?
当我在 Home() 以外的任何小部件中尝试这样做时,我收到错误消息:
错误:无法在此车辆小部件上方找到正确的提供商
例如,在我的小部件 Vehicles 中:
class Vehicles extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
final employee = Provider.of<Employee>(context);
...
User Provider 工作正常,我可以打印出来,但是 employee provider 不工作。
跟语境有关吗?谢谢,如有任何建议,我们将不胜感激。
我如何使用此事件的凸起按钮从 Home() 导航到 Vehicles() 小部件:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Vehicles())
);
},
这里有一个解释更详细的回复,因此我认为有些人会遇到这个问题,而且我也认为要解决这个问题有点棘手,尤其是当您的 Firestore 中有规则要求用户获得访问权限时数据库。
但通常,您希望围绕 MaterialApp()
.
所以我将向您展示一个简单的示例,以便于您理解它。
//The App() handles makes the providers globally accessible
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FirebaseAuthProviderLayer(
child: AuthorizedProviderLayer(
authorizedChild: MatApp(child: StartSwitch()),
unAuthorizedChild: MatApp(child: SignInScreen()),
),
);
}
}
//The MaterialApp Wrapped so that it not has to be rewritten
class MatApp extends StatelessWidget {
Widget child;
MatApp({this.child});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App',
home: child,
);
}
}
class FirebaseAuthProviderLayer extends StatelessWidget {
final Widget child;
FirebaseAuthProviderLayer({this.child});
@override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: FirebaseAuth.instance.authStateChanges(),
child: child,
);
}
}
//And the layer that decides either or not we should attach all the providers that requires the user to be authorized.
class AuthorizedProviderLayer extends StatelessWidget {
Widget authorizedChild;
Widget unAuthorizedChild;
AuthorizedProviderLayer({this.unAuthorizedChild, this.authorizedChild});
User user;
final FirestoreService firestoreService =
FirestoreService(); //The Service made to access Firestore
@override
Widget build(BuildContext context) {
user = Provider.of<User>(context);
if (user is User)
return MultiProvider(
providers: [
StreamProvider<FirestoreUserData>.value(
value: firestoreService.streamUser(),
),
StreamProvider<AppSettings>.value(
value: firestoreService.streamSettings(),
initialData: null,
)
],
child: authorizedChild,
);
return unAuthorizedChild;
}
}