将用户 uid 传递给 Flutter 中的 Firestore 流查询
Pass user uid to Firestore stream query in Flutter
- 我在这里使用 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) 只是一个 class.
请帮我解决问题。
编辑:
我试过修改,结果如下:
在对 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,后者再次在小部件树中使用。在你的帮助下,我似乎快到了。如果您不介意,请告诉我您对屏幕上的提供商错误的看法。非常感谢。
您可以尝试 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();
}
}
这似乎有效 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);
- 我在这里使用 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) 只是一个 class.
请帮我解决问题。
编辑:
我试过修改,结果如下:
在对 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,后者再次在小部件树中使用。在你的帮助下,我似乎快到了。如果您不介意,请告诉我您对屏幕上的提供商错误的看法。非常感谢。
您可以尝试 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();
}
}
这似乎有效 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);