You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularFire2谷歌登录组件获取用户数据返回undefined问题排查

问题根源分析

Hey there, let's break down why you're seeing undefined when calling getUserDetails():

The core issue here is asynchronous behavior. Your UserService initializes userData inside the subscription to afAuth.authState—this subscription runs asynchronously. When your AppComponent calls getUserDetails() in ngOnInit(), that subscription hasn't had time to fire yet, so userData is still its initial undefined value.

Firebase's auth state takes a moment to resolve (whether it's loading from local storage or verifying with the server), and your synchronous call to getUserDetails() happens before that process finishes.


解决方案

Here are two solid ways to fix this:

Instead of relying on a synchronous userData property, let your component subscribe to the auth state observable directly. This ensures you always get the latest user data as soon as it's available.

Update UserService:

import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class UserService {
  // Keep the auth state observable exposed
  user$: Observable<firebase.User | null>;

  constructor(public afAuth:AngularFireAuth) {
    this.user$ = this.afAuth.authState;
    // You can still subscribe here for service-internal logic
    this.user$.subscribe((user)=> {
      if(user){
        console.log(user.displayName);
      }
    });
  }

  signInWithGmail(){
    this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
  }

  signOut(){
    this.afAuth.auth.signOut();
  }

  // No need for getUserDetails anymore, just use user$ directly
}

Update AppComponent:

import { Component } from '@angular/core';
import { UserService } from './user.service'
import { OnInit } from '@angular/core/src/metadata/lifecycle_hooks';
import * as firebase from 'firebase';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  userDetail: firebase.User | null;

  constructor(public userService: UserService){}

  ngOnInit(){
    // Subscribe to the user observable to get real-time updates
    this.userService.user$.subscribe(user => {
      this.userDetail = user;
      console.log('User details:', user); // This will log the user once auth state resolves
    });
  }

  onSubmit(){
    this.userService.signInWithGmail();
  }

  onLogOut(){
    this.userService.signOut();
    console.log("Logged Out!");
  }
}

2. Use a BehaviorSubject to cache user state

If you prefer to maintain a cached user object in your service, use a BehaviorSubject to store the latest auth state. This lets you get the current user synchronously (if it's already loaded) or wait for it if not.

Update UserService:

import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase';
import { BehaviorSubject, Observable } from 'rxjs';
import { first } from 'rxjs/operators';

@Injectable()
export class UserService {
  private userSubject = new BehaviorSubject<firebase.User | null>(null);
  user$: Observable<firebase.User | null> = this.userSubject.asObservable();
  userData: firebase.User | null = null;

  constructor(public afAuth:AngularFireAuth) {
    this.afAuth.authState.subscribe((user)=> {
      this.userData = user;
      this.userSubject.next(user);
      if(user){
        console.log(user.displayName);
      }
    });
  }

  signInWithGmail(){
    this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
  }

  signOut(){
    this.afAuth.auth.signOut();
  }

  // Get user details as a promise (waits for auth state if not loaded)
  async getUserDetails(): Promise<firebase.User | null> {
    if (this.userData) {
      return this.userData;
    }
    // Wait for the first emission of the auth state
    return this.user$.pipe(first()).toPromise();
  }
}

Update AppComponent:

import { Component } from '@angular/core';
import { UserService } from './user.service'
import { OnInit } from '@angular/core/src/metadata/lifecycle_hooks';
import * as firebase from 'firebase';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  userDetail: firebase.User | null;

  constructor(public userService: UserService){}

  async ngOnInit(){
    // Wait for the user data to load before logging it
    this.userDetail = await this.userService.getUserDetails();
    console.log('User details:', this.userDetail);
  }

  onSubmit(){
    this.userService.signInWithGmail();
  }

  onLogOut(){
    this.userService.signOut();
    console.log("Logged Out!");
  }
}

Key Takeaway

Always remember that Firebase auth operations (and most AngularFire operations) are asynchronous. Avoid trying to access async data synchronously—use Observables or Promises to handle the timing correctly.

内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:52:03