将用户 uid 传递给 Flutter 中的 Firestore 流查询

Pass user uid to Firestore stream query in Flutter

  1. 我在这里使用 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,
          ),
      ],

  1. 我的问题 正在将 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();
  }
}

  1. 这里我使用的是小部件树下方的列表。
  @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 进行这些更改之前,当我进入它曾经工作的屏幕时,从提供商处收到这个严重错误。

这里是 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);