将用户 uid 传递给 Flutter 中的 Firestore 流查询
Posted
技术标签:
【中文标题】将用户 uid 传递给 Flutter 中的 Firestore 流查询【英文标题】:Pass user uid to Firestore stream query in Flutter 【发布时间】:2020-10-17 05:45:40 【问题描述】:-
这里我使用 main.dart 中的提供程序从文档中流式传输“itemsInUserDocument”数据。
Widget build(BuildContext context)
return MultiProvider(
providers: [
StreamProvider<DocumentSnapshot>.value(
value: DatabaseService().itemsInUserDocument, <--- (1) Providing here
),
StreamProvider<User>.value(
value: AuthProvider().user,
),
],
-
我的问题是在此处将 userUID 传递给 Stream 查询。我在 Firestore 上的文档 ID 是我的 userUID。
final userUID = "3SlUigYBgsNgzjU8a9GSimhAhuu1"; <-- (2) Need to pass to stream "userID' below??
class DatabaseService
Stream<DocumentSnapshot> get itemsInUserDocument
final DocumentReference userData = Firestore.instance.collection('userdata').document(userUID);
return userData.snapshots();
-
这里我使用的是小部件树中的列表。
@override
Widget build(BuildContext context)
final userTaskDone = Provider.of<DocumentSnapshot>(context);
List taskList = []; <-- (3) Using the list here.
taskList = userTaskDone['tasks'].toList();
print(taskList);
它目前有效,我现在正在第 (3) 节中获取流数据,但我需要将 Firebase 用户 UID 传递到第 (2) 节中的流中。
我可以使用 setState 函数在有状态小部件中获取用户 UID,但我尝试过的一切都不起作用,或者我似乎重复了太多东西,我正在尝试使用 Provider 来正确管理状态。
我也可以通过提供者获取 userUID,但您只能在(上下文)上使用它,其中我的通知程序部分 (2) 只是一个类。
请帮我解决。
编辑:
我已经尝试过修改,结果如下:
当我进入在对 main.dart 进行这些更改之前它曾经工作的屏幕时,从提供者那里得到这个严重错误。
这里是 main.dart 的完整代码,现在进行了编辑:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
title: 'Sendr',
home: MainScreen(),
routes:
SplashPage.id: (context) => SplashPage(),
LoginScreen.id: (context) => LoginScreen(),
NavigatorScreen.id: (context) => NavigatorScreen(),
CragSelectionScreen.id: (context) => CragSelectionScreen(),
CragRoutesScreen.id: (context) => CragRoutesScreen(),
RouteDetailScreen.id: (context) => RouteDetailScreen(),
MapScreen.id: (context) => MapScreen(),
,
);
///Authentication Logic
class MainScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return StreamProvider<User>.value(
value: AuthProvider().user,
child: Consumer<User>(
builder: (context, user, __)
if (user == null)
return LoginScreen();
else
return MultiProvider(
providers: [
Provider<DatabaseService>.value(
value: DatabaseService(user.uid),
),
],
child: NavigatorScreen(),
);
,
),
);
这是我的数据库服务:
import 'package:cloud_firestore/cloud_firestore.dart';
class DatabaseService
DatabaseService(this.uid);
final String uid;
Stream<DocumentSnapshot> get itemsInUserDocument
final DocumentReference userData =
Firestore.instance.collection('userdata').document(uid);
return userData.snapshots();
我没有对我正在使用它的步骤 (3) 进行任何更改,这可能是我现在的问题吗?
我正在尝试对此进行更多研究。通过提供者文档工作。如果我正确理解您的建议,我们将从顶部的 AuthProvider 流式传输 User 值,然后使用其下方的 User 值,然后将 user.uid 值传递给 DatabaseService,该值再次在小部件树下使用。在你的帮助下,我似乎快到了。如果您不介意,请告诉我您对屏幕上的提供程序错误的看法。非常感谢。
【问题讨论】:
【参考方案1】:您可以尝试使用来自rxdart
的switchmap
,它会侦听流T
并将其映射到S
之一。
Stream<S> switchMap<S>(Stream<S> Function(T value) mapper) =>
transform(SwitchMapStreamTransformer<T, S>(mapper));
import 'package:rxdart/transformers.dart';
final userStream = AuthProvider().user;
final itemsStream = userStream.switchMap<DocumentSnapshot>(
(user)
if (user == null) return Stream<DocumentSnapshot>.value(null);
return itemsCollection.where('uid', isEqualTo: user.uid).snapshots();
,
);
StreamProvider<DocumentSnapshot>.value(
value: itemsStream,
),
暂时写下来,这样可能是错的。
编辑
另一种方法是将您的项目提供者置于用户之下一级。这样您就可以定期使用用户 uid 值。
return StreamProvider<User>.value(
value: AuthProvider().user,
child: Consumer<User>(
builder: (_, user, __)
if (!user)
// Not logged in
else
return MultiProvider(
providers: [
Provider.value<DatabaseService>(
value: DatabaseService(user.uid),
),
// More services that rely on user.uid
],
child: SizedBox(),
);
,
),
);
2 编辑
class DatabaseService
DatabaseService(this.uid);
final String uid;
getData()
return MyCollection.where('uid', isEqualTo: uid).snapshots();
【讨论】:
我没有使用 rxdart 的经验,但我会调查一下,谢谢您的回答。我认为有一种更简单的方法可以将用户 uid 变量从全局变量或其他东西传递到查询中。我很难理解为什么这很难做到。 是的,您最简单的选择是ProxyStreamProvider
,但这并不是真的。详情见this issue
简而言之,我的问题是“如何在您的应用程序中的任何位置提供 userUID?” - 如果有人能回答这个问题,那将非常有帮助。
添加了另一种方法。您不一定需要使用消费者。您还可以使用Builder
,然后在其构建器方法中或树的该部分下方的任何位置调用final user = Provider.of<User>(context)
以检索该用户
非常感谢您的建议,我已经坐了好几天了,我想试试这个。但我不确定如何实施。在我的步骤 (2) 中,这是一个单独的文件,其中“DatabaseService”类是我需要该 uid 变量的地方,我将如何在此文件中使用它?【参考方案2】:
这似乎已经使 main.dart 看起来如下:
Main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return StreamProvider<User>.value(
value: AuthProvider().user,
child: Consumer<User>(
builder: (context, user, __)
if (user == null)
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
title: 'Sendr',
home: LoginScreen(),
);
else
return MultiProvider(
providers: [
StreamProvider<DocumentSnapshot>.value(
value: DatabaseService(user.uid).userRoutesDone,
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
title: 'Sendr',
home: NavigatorScreen(),
routes:
SplashPage.id: (context) => SplashPage(),
LoginScreen.id: (context) => LoginScreen(),
NavigatorScreen.id: (context) => NavigatorScreen(),
MapScreen.id: (context) => MapScreen(),
,
),
);
,
),
);
我的通知者:
import 'package:cloud_firestore/cloud_firestore.dart';
class DatabaseService
DatabaseService(this.uid);
final String uid;
Stream<DocumentSnapshot> get itemsInUserDocument
final DocumentReference userData =
Firestore.instance.collection('userdata').document(uid);
return userData.snapshots();
我在小部件树中使用它的位置:
@override
Widget build(BuildContext context)
final userTaskDone = Provider.of<DocumentSnapshot>(context);
List taskList = []; <-- (3) Using the list here.
taskList = userTaskDone['tasks'].toList();
print(taskList);
【讨论】:
以上是关于将用户 uid 传递给 Flutter 中的 Firestore 流查询的主要内容,如果未能解决你的问题,请参考以下文章
如何将用户的TextFormField输入传递给flutter中不同类的按钮
Flutter:如何将值从 streamprovider / listview builder 传递给另一个类
从firebase数据库flutter中的uid获取用户数据