将用户uid传递到Flutter中的Firestore流查询 [英] Pass user uid to Firestore stream query in Flutter

查看:66
本文介绍了将用户uid传递到Flutter中的Firestore流查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  1. 在这里,我正在main.dart中使用provider来流式传输"itemsInUserDocument"来自文档的数据.

 窗口小部件build(BuildContext context){返回MultiProvider(提供者:[StreamProvider< DocumentSnapshot> .value(值:DatabaseService().itemsInUserDocument,< ---(1)在此处提供),StreamProvider< User> .value(值:AuthProvider().user,),], 

  1. 我的问题正在此处将userUID传递到Stream查询.我在Firestore上的文档ID是我的userUID.

 最终用户UID ="3SlUigYBgsNgzjU8a9GSimhAhuu1";<-(2)是否需要传递到下面的流"userID"?类DatabaseService {流< DocumentSnapshot>获取itemsInUserDocument {最终的DocumentReference userData = Firestore.instance.collection('userdata').document(userUID);返回userData.snapshots();}} 

  1. 我在这里使用小部件树中的列表.

  @override窗口小部件build(BuildContext context){final userTaskDone = Provider.of< DocumentSnapshot>(上下文);列出taskList = [];<-(3)在此使用列表.taskList = userTaskDone ['tasks'].toList();打印(任务清单); 

  • 它当前可以正常工作,现在我可以在第(3)节中获取流数据,但是我需要将Firebase用户UID传递到第(2)节中的流中.

  • 我可以使用setState函数在有状态的小部件中获取用户UID,但我尝试过的所有方法都无法正常工作,或者好像我在重复很多事情,我试图使用Provider来正确管理状态./p>

  • 我也可以通过provider获取userUID,但是您只能在(通知者)通知者部分(2)只是一个类的(上下文)上使用它.

  • 请帮助我解决问题.

我尝试了修改,结果如下:

在对main.dart进行这些更改之前,当我进入其曾经工作过的屏幕时,会从提供商那里得到这个严重错误.

这是main.dart的完整代码,带有现在的修改:

  void main()=>runApp(MyApp());MyApp类扩展了StatelessWidget {@override窗口小部件build(BuildContext context){返回MaterialApp(debugShowCheckedModeBanner:否,主题:ThemeData.dark(),标题:"Sendr",主页:MainScreen(),路线:{SplashPage.id :(上下文)=>SplashPage(),LoginScreen.id :(上下文)=>LoginScreen(),NavigatorScreen.id :(上下文)=>NavigatorScreen(),CragSelectionScreen.id :(上下文)=>CragSelectionScreen(),CragRoutesScreen.id :(上下文)=>CragRoutesScreen(),RouteDetailScreen.id :(上下文)=>RouteDetailScreen(),MapScreen.id :(上下文)=>MapScreen(),},);}}///身份验证逻辑MainScreen类扩​​展了StatelessWidget {@override窗口小部件build(BuildContext context){返回StreamProvider< User> .value(值:AuthProvider().user,子级:消费者<用户>(生成器:(上下文,用户__){如果(使用者==空值){返回LoginScreen();} 别的 {返回MultiProvider(提供者:[提供程序< DatabaseService> .value(值:DatabaseService(user.uid),),],子级:NavigatorScreen(),);}},),);}} 

这是我的数据库服务:

  import'package:cloud_firestore/cloud_firestore.dart';类DatabaseService {DatabaseService(this.uid);最终的字符串uid;流< DocumentSnapshot>获取itemsInUserDocument {最终DocumentReference userData =Firestore.instance.collection('userdata').document(uid);返回userData.snapshots();}} 

我在使用它的步骤(3)上没有做任何更改,这可能是我现在遇到的问题吗?

我正在尝试对此进行更多研究.通过提供者文档进行工作.如果我正确理解了您的建议,我们将从顶部的AuthProvider流传输User值,然后在其下方使用User值,然后将user.uid值传递给DatabaseService,该值将再次在小部件树中使用.看起来我在您的帮助下快到了.如果您不介意,请让我知道您对屏幕上的提供程序错误的看法.非常感谢.

解决方案

您可以尝试通过 rxdart 中的 switchmap 监听并映射流 T S 之一.

  Stream< S>switchMap< S>(流< S>功能(T值)映射器)=>transform(SwitchMapStreamTransformer< T,S>(映射器)); 

  import'package:rxdart/transformers.dart';final userStream = AuthProvider().user;final itemsStream = userStream.switchMap< DocumentSnapshot>((用户){如果(用户== null)返回Stream< DocumentSnapshot> .value(null);返回itemsCollection.where('uid',isEqualTo:user.uid).snapshots();},); 

  StreamProvider< DocumentSnapshot> .value(值:itemStream,), 

将其写在袖套上,这样可能是错误的.

编辑

另一种方法是将商品提供者置于用户下方一级.这样,您就可以定期使用用户uid值.

 返回StreamProvider< User> .value(值:AuthProvider().user,子级:消费者<用户>(生成器:(_,用户,__){如果(!user){//未登录} 别的 {返回MultiProvider(提供者:[Provider.value< DatabaseService>(值:DatabaseService(user.uid),),//更多依赖user.uid的服务],子级:SizedBox(),);}},),); 

2修改

  class DatabaseService {DatabaseService(this.uid);最终的字符串uid;getData(){返回MyCollection.where('uid',isEqualTo:uid).snapshots();}} 

  1. Here I am using provider in main.dart to stream "itemsInUserDocument" data from a document.


Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
          StreamProvider<DocumentSnapshot>.value(
          value: DatabaseService().itemsInUserDocument,      <--- (1) Providing here
          ),
          StreamProvider<User>.value(
          value: AuthProvider().user,
          ),
      ],

  1. My problem is passing the userUID to the Stream query here. My document id's on Firestore is my 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. Here I am using the list in down the widget tree.

  @override
  Widget build(BuildContext context) {
    final userTaskDone = Provider.of<DocumentSnapshot>(context);

    List taskList = [];    <-- (3) Using the list here. 

    taskList = userTaskDone['tasks'].toList();

    print(taskList);


  • It currently works and I am getting the streamed data in section (3) as is now, but I need to pass the Firebase user UID into the stream in section (2).

  • I can get the user UID in a stateful widget with setState function but everything I have tried doesn't work or seems like I am duplicating things too much, I am trying to use Provider to manage state properly.

  • I can get the userUID with provider as well, but you can only use it on a (context), where my notifier section (2) is only a class.

  • PLEASE help me with a solution.

EDIT:

I have tried the edits and the result is as follow:

Getting this critical error from provider when I enter the screen where it used to work before these changes to main.dart.

Here is the full code for main.dart with edits as it is now:

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(),
            );
          }
        },
      ),
    );
  }
}

This is my Database Service:

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();
  }
}

I have made no change to my step (3) where I am using it, is this where my problem might be now?

I am trying to do more research on this. Working through the provider docs. If I understand your suggestion correctly, we are streaming the User value from AuthProvider at the top, then consume the User value just below it then passing the user.uid value to the DatabaseService, which is used down the widget tree again. Looks like I am almost there from your help. If you don't mind, please let me know what you think of the provider error on the screen. Much appreciated.

解决方案

You could try a switchmap from rxdart which listens to and maps a stream T to one of 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,
),

Writing this off the cuff so it might be wrong.

Edit

Another way would just be to place your items provider one level below your user. That way you can just regularly consume the user uid value.

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 Edit

class DatabaseService {
  DatabaseService(this.uid);

  final String uid;

  getData() {
    return MyCollection.where('uid', isEqualTo: uid).snapshots();
  }
}

这篇关于将用户uid传递到Flutter中的Firestore流查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆