开发者问题收集

如何获取与 Firestore 中 authUser 相关的用户数据库详细信息?

2020-01-09
7462

我正在尝试弄清楚如何获取用户名,该用户名是存储在用户集合中的属性,该属性已与 Firebase 身份验证模型创建的属性合并。

我可以访问 authUser - 它为我提供了 firebase 在身份验证工具中收集的有限字段,然后我尝试从那里获取相关的用户集合(使用相同的 uid)。

我有一个反应上下文消费者:

import React from 'react';
const AuthUserContext = React.createContext(null);
export default AuthUserContext;

然后在我的组件中我尝试使用:

const Test = () => (

<AuthUserContext.Consumer>
    {authUser => (

    <div>
            {authUser.email} // I can access the attributes in the authentication collection 
            {authUser.uid.user.name} //i cannot find a way to get the details in the related user collection document - where the uid on the collection is the same as the uid on the authentication table


     </div>
    )}
</AuthUserContext.Consumer>
);

const condition = authUser => !!authUser;
export default compose(
withEmailVerification,
withAuthorization(condition),
)(Test);

在我的 firebase.js 中 - 我认为我已尝试将身份验证模型中的 authUser 属性与用户集合属性合并,如下所示:

class Firebase {
  constructor() {
    app.initializeApp(config).firestore();
    /* helpers */
    this.fieldValue = app.firestore.FieldValue;


    /* Firebase APIs */
    this.auth = app.auth();
    this.db = app.firestore();

onAuthUserListener = (next, fallback) =>
    this.auth.onAuthStateChanged(authUser => {
      if (authUser) {
        this.user(authUser.uid)
          .get()
          .then(snapshot => {
            const dbUser = snapshot.data();
            // default empty roles
            if (!dbUser.roles) {
              dbUser.roles = {};
            }
            // merge auth and db user
            authUser = {
              uid: authUser.uid,
              email: authUser.email,
              emailVerified: authUser.emailVerified,
              providerData: authUser.providerData,
              ...dbUser,
            };
            next(authUser);
          });
      } else {
        fallback();
      }
    });

我找不到从 authUser(可让我获取身份验证属性)获取到具有与身份验证集合中相同的 uid 的 id 的用户集合的方法。

我见过 这篇文章 ,它似乎有同样的问题,并试图找出答案应该暗示什么 - 但我似乎找不到一种可行的方法从身份验证集合到用户集合,我不知道如果它没有让我访问来自 authUser 的用户集合上的属性,合并对我有什么作用。

我试图在我的 firebase.js 中使用一个助手来给我一个来自 uid 的用户 - 但这似乎也无济于事。

user = uid => this.db.doc(`users/${uid}`);
  users = () => this.db.collection('users');

下一次尝试

为了添加更多背景信息,我制作了一个可以记录(但不能渲染)authUser 的测试组件,如下所示:

import React, { Component } from 'react';
import { withFirebase } from '../Firebase/Index';
import { Button, Layout  } from 'antd';

import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';


class Test extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: null,
      ...props.location.state,
    };
  }

  componentDidMount() {
    if (this.state.user) {
      return;
    }

    this.setState({ loading: true });

    // this.unsubscribe = this.props.firebase
    //   .user(authUser.uid)
    //   .onSnapshot(snapshot => {
    //     const userData = snapshot.data();  
    //     console.log(userData);
    //     this.setState({
    //       user: snapshot.data(),
    //       loading: false,
    //     });
    //   });
  }

  componentWillUnmount() {
    this.unsubscribe && this.unsubscribe();
  }



  render() {
    const { user, loading } = this.state;


    return (
        <div>
        <AuthUserContext.Consumer>
        {authUser => (
            console.log(authUser),
            <p>
                </p>


            )}
            </AuthUserContext.Consumer> 

        </div>

    );

    };
}
export default Test;

日志显示了日志中没有 uid、email 等,但它位于一长串项目之中 - 其中许多项目以 1 或 2 个字母开头(我找不到关键字来找出每个前缀字母的含义)。下面提取的示例:

在此处输入图像描述

此评论的更新:

之前,我说过: uid、email 等字段似乎没有嵌套在这些前缀下,但如果我尝试:

 console.log(authUser.email)

,我会收到一条错误消息:

TypeError: Cannot read property 'email' of null

更新: 我刚刚意识到,在控制台日志中,我必须展开一个标记为:

Q {I: Array(0), l:

的下拉菜单,才能查看电子邮件属性。有人知道这些胡言乱语是什么意思吗?我找不到关键点来弄清楚 Q、I 或 l 是什么意思,也不知道我是否应该引用这些东西来获取身份验证表中的相关属性。也许如果我能弄清楚 - 我可以找到一种方法来使用身份验证集合中的 uid 来获取用户集合。

是否有人在前端使用过 react,并使用上下文消费者来找出当前用户是谁?如果是这样,您如何在身份验证模型上访问他们的属性,以及如何访问相关用户集合上的属性(其中用户文档上的 docId 是身份验证表中的 uid)?

下次尝试

下次尝试产生了非常奇怪的结果。

我有 2 个单独的页面,它们是上下文消费者。它们之间的区别在于一个是函数,另一个是类组件。

在函数组件中,我可以呈现 {authUser.email}。当我尝试在类组件中执行相同的操作时,出现以下错误:

TypeError: Cannot read property 'email' of null

此错误来自具有相同登录用户的同一会话。

注意:虽然 Firebase 文档说 currentUser 属性在 auth 上可用 - 但我根本无法使其工作。

我的函数组件有:

import React from 'react';
import { Link } from 'react-router-dom';
import { compose } from 'recompose';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';


const Account = () => (

<AuthUserContext.Consumer>
    {authUser => (
    <div>
         {authUser.email}
    </div>
    )}
</AuthUserContext.Consumer>
);

// const condition = authUser => !!authUser;
// export default compose(
// withEmailVerification,
// withAuthorization(condition),
// )(Account);
export default Account;

虽然我无法获取用户集合属性,其中用户文档上的 docId 与经过身份验证的用户的 uid 相同,但从此组件中,我可以输出此用户的 auth 集合上的电子邮件属性。

虽然 Firebase 文档 在此处提供了有关管理用户和访问属性的建议,我还没有找到在 React 中实现这种方法的方法。每次尝试这样做,无论是在我的 firebase.js 中创建助手,还是尝试在组件中从头开始,都会在访问 firebase 时产生错误。但是,我可以生成用户列表及其相关的用户集合信息(我无法根据 authUser 是谁来获取用户)。

我的类组件有:

import React from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch,

  } from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';



class Dashboard extends React.Component {
  state = {
    collapsed: false,
  };

  onCollapse = collapsed => {
    console.log(collapsed);
    this.setState({ collapsed });
  };

  render() {
    const {  loading } = this.state;
    // const dbUser = this.props.firebase.app.snapshot.data();
    // const user = Firebase.auth().currentUser;
    return (
    <AuthUserContext.Consumer>
      {authUser => (  

        <div>    
         {authUser.email} // error message as shown above
          {console.log(authUser)} // output logged in amongst a long list of menus prefixed with either 1 or 2 characters. I can't find a key to decipher what these menus mean or do.
        </div>
      )}
    </AuthUserContext.Consumer>  
    );
  }
}

//export default withFirebase(Dashboard);
export default Dashboard;

在我的 AuthContext.Provider 中 - 我有:

import React from 'react';
import { AuthUserContext } from '../Session/Index';
import { withFirebase } from '../Firebase/Index';
const withAuthentication = Component => {
  class WithAuthentication extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        authUser: null,
      };  
    }

    componentDidMount() {
      this.listener = this.props.firebase.auth.onAuthStateChanged(
        authUser => {
          authUser
            ? this.setState({ authUser })
            : this.setState({ authUser: null });
        },
      );
    }

    componentWillUnmount() {
      this.listener();
    };  

    render() {
      return (
        <AuthUserContext.Provider value={this.state.authUser}>
          <Component {...this.props} />
        </AuthUserContext.Provider>
      );
    }
  }
  return withFirebase(WithAuthentication);

};
export default withAuthentication;

下一次尝试

很奇怪,通过这次尝试,我试图在控制台记录我可以看到存在于数据库中的值,并且 name 的值被返回为“未定义”,而数据库中有一个字符串。

这次尝试有:

    import React from 'react';
    import {
        BrowserRouter as Router,
        Route,
        Link,
        Switch,
        useRouteMatch,
     } from 'react-router-dom';
    import * as ROUTES from '../../constants/Routes';
    import { compose } from 'recompose';
    import { withFirebase } from '../Firebase/Index';
    import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';



    class Dash extends React.Component {
      // state = {
      //   collapsed: false,
      // };

      constructor(props) {
        super(props);

        this.state = {
          collapsed: false,
          loading: false,
          user: null,
          ...props.location.state,
        };
      }
      componentDidMount() {
        if (this.state.user) {
          return;
        }

        this.setState({ loading: true });

        this.unsubscribe = this.props.firebase
          .user(this.props.match.params.id)
          // .user(this.props.user.uid)
          // .user(authUser.uid)
          // .user(authUser.id)
          // .user(Firebase.auth().currentUser.id)
          // .user(Firebase.auth().currentUser.uid)

          .onSnapshot(snapshot => {
            this.setState({
              user: snapshot.data(),
              loading: false,
            });
          });
      }

      componentWillUnmount() {
        this.unsubscribe && this.unsubscribe();
      }


      onCollapse = collapsed => {
        console.log(collapsed);
        this.setState({ collapsed });
      };

      render() {
        // const {  loading } = this.state;
        const { user, loading } = this.state;
        // let match = useRouteMatch();
        // const dbUser = this.props.firebase.app.snapshot.data();
        // const user = Firebase.auth().currentUser;
        return (
        <AuthUserContext.Consumer>
          {authUser => (  

            <div>    
            {loading && <div>Loading ...</div>}

                <Layout style={{ minHeight: '100vh' }}>
                  <Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
                    <div  />

                  </Sider>
                <Layout>

                    <Header>
                    {console.log("authUser:", authUser)}
                    // this log returns the big long list of outputs - the screen shot posted above is an extract. It includes the correct Authentication table (collection) attributes
                    {console.log("authUser uid:", authUser.uid)}
                    // this log returns the correct uid of the current logged in user
                    {console.log("Current User:", this.props.firebase.auth.currentUser.uid)}
// this log returns the correct uid of the current logged in user
                    {console.log("current user:", this.props.firebase.db.collection("users").doc(this.props.firebase.auth.currentUser.uid
                    ))}
// this log returns a big long list of things under a heading: DocumentReference {_key: DocumentKey, firestore: Firestore, _firestoreClient: FirestoreClient}. One of the attributes is: id: (...) (I can't click to expand this).
                    {console.log("current user:", this.props.firebase.db.collection("users").doc(this.props.firebase.auth.currentUser.uid
                    ).name)}
//this log returns: undefined. There is an attribute in my user document called 'name'. It has a string value on the document with the id which is the same as the currentUser.uid.
                    <Text style={{ float: 'right', color: "#fff"}}>

                      {user && (
                        <Text style={{ color: "#fff"}}>{user.name}
//this just gets skipped over in the output. No error but also does not return the name.
</Text>


                      )}

                    </Text>
                    </Header>      
                   </Layout>
                </Layout>

            </div>
          )}
        </AuthUserContext.Consumer>  
        );
      }
    }

    export default withFirebase(Dash);

下一次尝试

所以这次尝试很笨拙,没有使用我上面尝试使用的帮助程序或快照查询,而是将用户集合文档属性记录到控制台如下:

{ this.props.firebase.db.collection('users').doc(authUser.uid).get()

      .then(doc => {
          console.log(doc.data().name) 
      })

    } 

但是我无法找到在 jsx 中呈现该名称的方法

您实际上如何打印输出?

当我尝试:

{ 


this.props.firebase.db.collection('users').doc(authUser.uid).get().data().name

                }

我收到一条错误消息:

TypeError: this.props.firebase.db.collection(...).doc(...).get(...).data is not a function

当我尝试:

{ 



this.props.firebase.db.collection('users').doc(authUser.uid).get()
              .then(doc => {
                  console.log(doc.data().name), 
                  <p>doc.data().name</p>
              })
            } 

我收到一条错误消息:

Line 281:23: Expected an assignment or function call and instead saw an expression no-unused-expressions

当我尝试:

{ 


this.props.firebase.db.collection('users').doc(authUser.uid).get("name")
              .then(doc => {
                  console.log(doc.data().name), 
                  <p>doc.data().name</p>
              })
            }

错误消息说:

Expected an assignment or function call and instead saw an expression

我准备放弃尝试找出如何使快照查询工作 - 如果我可以让用户集合的名称呈现在屏幕上。有人可以帮忙完成这一步吗?

下次尝试

我找到了 这个帖子 。它很好地解释了需要发生的事情,但我无法按所示实现它,因为 componentDidMount 不知道 authUser 是什么。

我目前的尝试如下 - 但是,按照目前的写法,authUser 是返回值的包装器 - 而 componentDidMount 段不知道 authUser 是什么。

import React from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch,
    useRouteMatch,
 } from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';




const { Title, Text } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;


class Dashboard extends React.Component {
  // state = {
  //   collapsed: false,
  //   loading: false,
  // };

  constructor(props) {
    super(props);

    this.state = {
      collapsed: false,
      loading: false,
      user: null,
      ...props.location.state,
    };
  }
  componentDidMount() {
    if (this.state.user) {
      return;
    }

    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .user(this.props.match.params.id)
      .onSnapshot(snapshot => {
        this.setState({
          user: snapshot.data(),
          loading: false,
        });
      });
  // }

//   firebase.firestore().collection("users")
//     .doc(this.state.uid)
//     .get()
//     .then(doc => {
//       this.setState({ post_user_name: doc.data().name });
//   });
// }

  this.props.firebase.db
    .collection('users')
    .doc(authUser.uid)
    .get()
    .then(doc => {
        this.setState({ user_name: doc.data().name });
        // loading: false,
      });  
    }                  

  componentWillUnmount() {
    this.unsubscribe && this.unsubscribe();
  }


  onCollapse = collapsed => {
    console.log(collapsed);
    this.setState({ collapsed });
  };

  render() {
    // const {  loading } = this.state;
    // const { user, loading } = this.state;
    // let match = useRouteMatch();
    // const dbUser = this.props.firebase.app.snapshot.data();
    // const user = Firebase.auth().currentUser;


    return (
    <AuthUserContext.Consumer>
      { authUser => (  

        <div>    

                <Header>

                 {/* 
                    { 
                    this.props.firebase.db.collection('users').doc(authUser.uid).get()
                    .then(doc => {
                        console.log( doc.data().name
)                          
                    })
                  } 
                  */} 


                  </Text>
                </Header>      

                      <Switch>

                      </Switch>    

        </div>
      )}
    </AuthUserContext.Consumer>  
    );
  }
}

export default withFirebase(Dashboard);

下一次尝试

接下来,我尝试将仪表板的路由包装在 AuthContext.Consumer 中,以便整个组件可以使用它 - 从而让我在 componentDidMount 函数中访问已登录的用户。

我将路由更改为:

<Route path={ROUTES.DASHBOARD} render={props => (
          <AuthUserContext.Consumer>
             { authUser => ( 
                <Dashboard authUser={authUser} {...props} />  
             )}
          </AuthUserContext.Consumer>
        )} />

并从仪表板组件渲染语句中删除了消费者。

然后在仪表板组件的 componentDidMount 中,我尝试:

componentDidMount() {
    if (this.state.user) {
      return;
    }

    this.setState({ loading: true });

     this.unsubscribe =
     this.props.firebase.db
     .collection('users')
   //.doc(this.props.firebase.db.collection('users').doc(this.props.firebase.authUser.uid))
 .doc(this.props.firebase.db.collection('users').doc(this.props.authUser.uid))
     .get()
     .then(doc => {
         this.setState({ name: doc.data().name });
       loading: false,
      });  
  }                  

当我尝试此操作时,出现一条错误消息:

FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: a custom DocumentReference object

下一步尝试 下面的人似乎在第一个提出的解决方案中找到了有用的东西。我没能从中找到任何有用的东西,但回顾它的建议,我很难理解 firebase 文档中的示例(它没有透露如何为 .doc() 请求提供 :uid 值),如下所示:

db.collection("cities").doc("SF");

  docRef.get().then(function(doc) {
      if (doc.exists) {
          console.log("Document data:", doc.data());
      } else {
          // doc.data() will be undefined in this case
          console.log("No such document!");
      }

与我在 componentDidMount 函数中的尝试根本不同,即:

this.unsubscribe =
  this.props.firebase.db
    .collection('users')
    // .doc(this.props.firebase.db.collection('users').doc(this.props.firebase.authUser.uid))
    // .doc(this.props.firebase.db.collection('users').uid: this.props.firebase.auth().currentUser.uid  )
    .doc(this.props.authUser.uid)
    .get()
    .then(doc => {
        this.setState({ user.name: doc.data().name });
        // loading: false,
      }else {
        // doc.data() will be undefined in this case
        console.log("Can't find this record");
      }

    );  
  }

也许解决该步骤是一个线索,将有助于推动这一结果。有人能找到更好的 firestore 文档来展示如何使用已登录用户侦听器 uid 获取用户集合记录吗?

为此,我可以从 FriendlyEats 代码实验室 示例 中看到,有人尝试在代码中为 id 搜索值赋予 doc.id。我不知道这段代码是用什么语言编写的 - 但它看起来确实与我尝试做的事情很相似 - 我只是不知道如何从该示例转移到我知道如何处理的东西。

display: function(doc) {
      var data = doc.data();
      data['.id'] = doc.id;
      data['go_to_restaurant'] = function() {
        that.router.navigate('/restaurants/' + doc.id);
      };
3个回答

从您问题的最后一行( users = () => this.db.collection('users'); )中,我了解到您存储用户额外信息的集合称为 users ,并且此集合中的用户文档使用 userId (uid) 作为 docId。

以下内容应该可以解决问题(未经测试):

class Firebase {
  constructor() {
    app.initializeApp(config).firestore();
    /* helpers */
    this.fieldValue = app.firestore.FieldValue;


    /* Firebase APIs */
    this.auth = app.auth();
    this.db = app.firestore();

onAuthUserListener = (next, fallback) =>
    this.auth.onAuthStateChanged(authUser => {
      if (authUser) {
           this.db.collection('users').doc(authUser.uid)
              .get()
              .then(snapshot => {
                const userData = snapshot.data();
                console.log(userData);
                //Do whatever you need with userData
                //i.e. merging it with authUser
                //......

                next(authUser);
          });
      } else {
        fallback();
      }
    });

因此,在通过 onAuthStateChanged() 方法设置的观察者内,当我们检测到用户已登录时(即在 if (authUser) { 中),我们使用其 uid 查询 users 集合中与此用户相对应的唯一文档(请参阅 读取一个文档 ,以及 get() 方法的文档)。

Renaud Tarnec
2020-01-09

我有一个理论,希望您能测试一下。

我认为,当您在 onAuthStateChanged 处理程序中调用 next(authUser) 时,在执行过程中会遇到错误(例如 无法读取未定义的属性“name”... )。

您的代码无法按预期工作的原因是因为您在调用 next(authUser) 时,它位于 Promise 链的 then() 内。Promise 内引发的任何错误都将被捕获,并导致 Promise 被拒绝。当 Promise 被拒绝时,它将使用错误调用其附加的错误处理程序。有问题的 Promise 链目前没有任何此类错误处理程序。

如果我弄糊涂了,请阅读 这篇博文 ,了解 Promises 速成课程,然后再回来。

那么我们该怎么做才能避免这种情况呢?最简单的方法是在 Promise then() 处理程序的范围 之外 调用 next(authUser) 。我们可以使用 window.setTimeout(function) 来实现此目的。

因此,在您的代码中,您需要将

next(authUser)

替换为

setTimeout(() => next(authUser))
// or setTimeout(() => next(authUser), 0) for the same result

这样会正常抛出任何错误,而不会被 Promise 链捕获。

重要的是,您没有一个用于处理 userDocRef.get() 失败情况的 catch 处理程序。因此,只需在 then() 末尾添加 .catch(() => setTimeout(fallback)) ,这样您的代码在出错时就会使用 fallback 方法。

所以我们最终得到:

this.user(authUser.uid)
  .get()
  .then(snapshot => {
    const dbUser = snapshot.data();
    // default empty roles
    if (!dbUser.roles) {
      dbUser.roles = {};
    }
    // merge auth and db user
    authUser = {
      ...dbUser, // CHANGED: Moved dbUser to beginning so it doesn't override other info
      uid: authUser.uid,
      email: authUser.email,
      emailVerified: authUser.emailVerified,
      providerData: authUser.providerData
    };
    setTimeout(() => next(authUser), 0); // invoke callback outside of Promise
  })
  .catch((err) => setTimeout(() => fallback(), 0)); // invoke callback outside of Promise

编辑的代码

上述解释应该允许您修复代码,但这是我对您的 Firebase 类的版本,其中包含各种易于使用的更改。

用法:

import FirebaseHelper from './FirebaseHelper.js';

const fb = new FirebaseHelper();
fb.onUserDataListener(userData => {
  // do something - user is logged in!
}, () => {
  // do something - user isn't logged in or an error occurred
}

类定义:

// granular Firebase namespace import
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

const config = { /* firebase config goes here */ };

export default class FirebaseHelper { // renamed from `Firebase` to prevent confusion
  constructor() {
    /* init SDK if needed */
    if (firebase.apps.length == 0) { firebase.initializeApp(config); }

    /* helpers */
    this.fieldValue = app.firestore.FieldValue;

    /* Firebase APIs */
    this.auth = firebase.auth();
    this.db = firebase.firestore();
  }

  getUserDocRef(uid) { // renamed from `user`
    return this.db.doc(`users/${uid}`);
  }

  getUsersColRef() { // renamed from `users`
    return this.db.collection('users');
  }

  /**
   * Attaches listeners to user information events.
   * @param {function} next - event callback that receives user data objects
   * @param {function} fallback - event callback that is called on errors or when user not logged in
   *
   * @returns {function} unsubscribe function for this listener
   */
  onUserDataListener(next, fallback) {
    return this.auth.onAuthStateChanged(authUser => {
      if (!authUser) {
        // user not logged in, call fallback handler
        fallback();
        return;
      }

      this.getUserDocRef(authUser.uid).get()
        .then(snapshot => {
          let snapshotData = snapshot.data();

          let userData = {
            ...snapshotData, // snapshotData first so it doesn't override information from authUser object
            uid: authUser.uid,
            email: authUser.email,
            emailVerified: authUser.emailVerifed,
            providerData: authUser.providerData
          };

          setTimeout(() => next(userData), 0); // escapes this Promise's error handler
        })
        .catch(err => {
          // TODO: Handle error?
          console.error('Error while getting user document -> ', err.code ? err.code + ': ' + err.message : (err.message || err));
          setTimeout(fallback, 0); // escapes this Promise's error handler
        });
    });
  }

  // ... other methods ...
}

请注意,在这个版本中, onUserDataListener 方法从 onAuthStateChanged 返回取消订阅函数。当您的组件被卸载时,您应该分离所有相关的监听器,这样您就不会发生内存泄漏,也不会在不需要时在后台运行损坏的代码。

class SomeComponent {
  constructor() {
    this._unsubscribe = fb.onUserDataListener(userData => {
      // do something - user is logged in!
    }, () => {
      // do something - user isn't logged in or an error occurred
    };
  }

  // later
  componentWillUnmount() {
    this._unsubscribe();
  }
}
samthecodingman
2020-01-14

在您的 AuthContext.Provider 实现中,您可以直接访问 SDK 的 onAuthStateChanged 侦听器:

componentDidMount() {
  this.listener = this.props.firebase.auth.onAuthStateChanged(
    authUser => {
      authUser
        ? this.setState({ authUser })
        : this.setState({ authUser: null });
    }
  );
}

应将其更改为使用辅助类中的 onAuthUserListener

componentDidMount() {
  this.listener = this.props.firebase.onAuthUserListener(
    /* next()     */ (authUserWithData) => this.setState({authUser: authUserWithData}),
    /* fallback() */ () => this.setState({authUser: null})
  );
}

关于充满大量随机属性的日志消息,这是因为 firebase.User 对象既具有 公共 API ,又具有 实现 ,其中包含许多私有属性和方法,这些属性和方法编译时已缩小。由于这些缩小的属性和方法未明确标记为不可枚举,因此它们包含在任何日志输出中。如果您只想记录实际有用的部分,则可以使用以下方法解构和重构对象:

// Extracts public properties of firebase.User objects
// see https://firebase.google.com/docs/reference/js/firebase.User#properties
function extractPublicProps(user) {
  let {displayName, email, emailVerified, isAnonymous, metadata, phoneNumber, photoURL, providerData, providerId, refreshToken, tenantId, uid} = user;
  return {displayName, email, emailVerified, isAnonymous, metadata, phoneNumber, photoURL, providerData, providerId, refreshToken, tenantId, uid}
}

function extractUsefulProps(user) {
  let {displayName, email, emailVerified, isAnonymous, phoneNumber, photoURL, uid} = user;
  return {displayName, email, emailVerified, isAnonymous, phoneNumber, photoURL, uid}
}

let authUser = firebase.auth().currentUser;
console.log(authUser);
console.log(extractPublicProps(authUser));
console.log(extractUsefulProps(authUser));
samthecodingman
2020-01-24