flutter - 如何在 Flutter (Dart) 中通过新路由获取子级 StreamProvider 数据
问题描述
我正在使用 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() 以外的任何小部件中尝试时,我收到错误:
错误:在此车辆小部件上方找不到正确的提供程序
例如,在我的小部件车辆中:
class Vehicles extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
final employee = Provider.of<Employee>(context);
...
用户提供者工作正常,我可以打印出来,但员工提供者不起作用。
它与上下文有关吗?谢谢,任何建议将不胜感激。
我如何使用带有此事件的凸起按钮从 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;
}
}
推荐阅读
- java - 尝试在 Java/NodeJS 中编码字符串(一次性密码)
- python - 修复了 plotly.express.timeline 中的条形宽度/厚度
- javascript - 在多个条件语句期间在 $(window).scroll 函数中执行一次
- audio - 如何在使用 FFmpeg.AutoGen 创建的 mp4 文件中包含音频?
- javascript - ReactJS Typescript 类型参数 '{ keyPrefix: string; }' 不可分配给字符串类型的参数
- python - 页面在程序关闭之前不会加载
- php - PHP: MATCH AGAINST 不适用于某些停用词,但适用于其他停用词(没有明显的逻辑)
- r - 使用 row_number() - R 时跳过特定观察
- flutter - ListView 和 Card Flutter 中的额外“空间”
- installation - Wikibase 安装问题