如何轻松地将Observable转换或分配给行为主题,以便其他组件可以共享它

时间:2017-01-20 04:03:54

标签: angular rxjs reactive-programming observable

我是Observable样式编程的新手。我有一个问题:我希望在组件之间跨应用程序共享用户信息 - 我使用BehaviorSubject来共享此信息。这是通过将BehaviorSubject共享为AuthInfo来启发的。如果我可以在我的应用程序组件中共享包含uid的AuthInfo,为什么我可以使用它来共享我的用户对象数据?

问题是,用户对象,我是从Firebase获得的。所以它是一个Observable,我不知道如何将它分配给一个行为主题。所以这是我尝试的代码:

  @Injectable()
  export class AuthService {

  static UNKNOWN_USER = new AuthInfo(null);

  static EMPTY_USER = new User(null, null, null, null);

  authInfo$: BehaviorSubject<AuthInfo> = new BehaviorSubject<AuthInfo>(AuthService.UNKNOWN_USER);

  userInfo$: BehaviorSubject<User> = new BehaviorSubject<User>(AuthService.EMPTY_USER);

  constructor(private auth: FirebaseAuth, private db:AngularFireDatabase, @Inject(FirebaseRef) fb) {

//firebase way to see if user is login or not
this.auth.subscribe(user => {
  if (user) {
    const authInfo = new AuthInfo(user.uid);
    this.authInfo$.next(authInfo);
    //This is the part I do not know how to do
    [OPTION 1]: this.userInfo$.next(findUserByuid(user.uid)) ?? - error
    [OPTION 2]: this.userInfo$ = findUserByuid(user.uid) ?? - userInfo$ turn into an observerable, which when I logout to call this.userInfo$.next(AuthService.EMPTY_USER) it will  throw error as .next() is not a function.
    [OPTION 3]:
    this.findUserByuid(user.uid).subscribe(user => {
      this.userInfo$.next(user);
    });
    ---- Can I put a subscribe inside of another subscribe to chain it like promise? I am not sure this is following the best practices. But this is the only option that there is no error. But just not sure I am doing it right. I do get the user object no problem

  }
  else {
    this.authInfo$.next(AuthService.UNKNOWN_USER);
  }
});


}

findUserByuid(uid:string):any {
   //return a firebase object observerable
   return this.db.object('userProfile/' + uid).map(user => User.fromJson(user));

}

logout() {

this.userInfo$.next(AuthService.EMPTY_USER);
this.authInfo$.next(AuthService.UNKNOWN_USER);
this.auth.logout();
}

更大的问题是,我应该使用行为主题在应用程序之间共享数据吗?或者我应该使用像用户$ = findUserByuid(uid)这样的observable,并将user $作为AuthService成员变量。然后其他组件只订阅用户$?

我对在Angular2上共享数据的最佳方法感到困惑,没有使用类似于旧方式Angular 1的虚拟服务。我看到ppl使用Behavior Subject分享auth状态 - 这就是为什么我有所有这些问题和实现。任何帮助将不胜感激!关于行为主题没有太多资源。

[更新]:我选择行为主题的原因,而不仅仅是observable在我的应用程序的不同部分之间传递数据: Behavior Subject VS regular Observable

2 个答案:

答案 0 :(得分:3)

这就是我写它的方式:

...

authInfo$: Observable<AuthInfo>;
userInfo$: Observable<User>;

constructor(private auth: FirebaseAuth, private db:AngularFireDatabase, @Inject(FirebaseRef) fb) {
  //firebase way to see if user is login or not
  this.authInfo$ = auth
    .startWith(null) // in case auth has no initial value
    .map(user => user ? new AuthInfo(user.uid) : AuthService.UNKNOWN_USER)
    .publishReplay(1)
    .refCount();

  // automatically update the unserInfo$ when authInfo$ changes (no matter from where)
  // ...we are "reacting" on the data emitted by authInfo$ ... hence the name "reactive" programming
  this.userInfo$ = this.authInfo$
    .switchMap(authInfo => this.findUserByuid(authInfo.uid))
    .publishReplay(1);

  // this activates the whole stream-flow
  this.userInfo$.connect(); // instead of .connect() you could also append a ".refCount()" after the ".publishReplay(1)", however then it would only be acitve when there is at least 1 subscriber, so it depends on what you want
}

findUserByuid(uid?: string): Observable<User> {
  if (uid == null) {
    return Observable.of(AuthService.EMPTY_USER);
  } else {
    return this.db.object('userProfile/' + uid)
      .map(user => User.fromJson(user));
  }
}

logout() {
  this.auth.logout();
}

...

答案 1 :(得分:2)

在我看来,两个人在应用程序中共享数据的最佳方式是使用在角度2中使用nxx / store加上ngrx / effects实现的redux模式。以及智能组件和表示组件模式。

我有一个关于这些模式的例子

https://github.com/vigohe/ionic2-marvelApp

我正在运行的例子:

https://enigmatic-plains-75996.herokuapp.com/

来自ngrx repo的官方示例:

https://github.com/ngrx/example-app

更多信息:

尝试学习它,因为它会改变你的生活;)