如何在 Flutter (Dart) 中通过新路由获取子级 StreamProvider 数据
Posted
技术标签:
【中文标题】如何在 Flutter (Dart) 中通过新路由获取子级 StreamProvider 数据【英文标题】:How to get StreamProvider data in children with new routes in Flutter (Dart) 【发布时间】:2021-02-26 19:29:33 【问题描述】:我正在使用 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())
);
,
【问题讨论】:
【参考方案1】:这里有一个更解释的回复,因此我认为有些人会遇到这个问题,而且我也认为解决这个问题有点棘手,尤其是当您的 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;
【讨论】:
嗨 Max,非常感谢您的详细回复,实际上我确实按照您在此处的推荐使用 MultiProvider 来完成这项工作,所以您的答案很准确,非常感谢。跨度>以上是关于如何在 Flutter (Dart) 中通过新路由获取子级 StreamProvider 数据的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 导航,必填参数,单独的路由文件,如何正确编码