我正在尝试返回一个由User和Results组成的UserDetail对象,通过Account的accessToken检索User(通过单个异步调用检索所有User)。目前,我仍想弄清楚如何导航到detailcomponent时如何返回此UserDetail对象(我知道由于调用是异步的,因此无法从字面上返回该对象,但是我需要在我的对象中使用该对象组件)。
下面的代码给我以下错误:
类型'Observable'不可分配给类型 “可观察”
我已经尝试过使用管道和映射,因为我已经阅读了这是如何将异步调用“返回”到调用该函数的组件的方法。然后,该组件应该可以处理订阅,但是如果不创建错误,我什至无法做到这一点。
@Injectable({
providedIn: 'root'
})
export class UserResolver implements Resolve<UserDetails> {
constructor(
private as: AccountService,
private rs: ResultService,
private auth: AuthService
) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<UserDetails> {
return this.as.getAccount(route.params['id']).pipe(
map((acc: Account) => {
this.as.getUserDetails(acc.access_token).pipe(
map((user: User) => {
if (user != null) {
this.rs.getResults(this.auth.token).pipe(
map((res: Result[]) => {
const ud: UserDetails = {
user,
results: res.filter(x => x.userId === acc.uid)
};
return of(ud);
})
);
}
})
);
})
);
答案 0 :(得分:1)
尝试使用switchMap
代替map
。 map
只是将一个值转换为另一个值,而switchMap
则允许您切换到另一个可观察的值。
在不了解发生了什么的情况下,我想您想要这样的东西:
let user: User;
let account: Account;
return this.as.getAccount(route.params['id']).pipe(
tap((acc: Account) => account = account),
switchMap((acc: Account) => this.as.getUserDetails(acc.access_token)),
// this filter will stop the next steps from running if the user is null
// it will also mean a value isn't emitted
// if you want to emit a null, you will need to modify the pipe
filter((u: User) => u !== null),
tap((u: User) => user = u),
switchMap((u: User) => this.rs.getResults(this.auth.token))
map((res: Result[]) => {
const ud: UserDetails = {
user,
results: res.filter(x => x.userId === account.uid)
};
return ud;
})
);
注意它不再像您那样缩进,而是一系列管道运算符。每当您要切换到新的可观察对象时,请使用switchMap
或concatMap
。我们仅使用map
将最后一个可观察到的结果映射到我们要从函数返回的值。
每当需要将状态保存到管道中间时,我都会使用tap来将其分配给变量。
此外,您正在(可能)对this.rs.getResults(this.auth.token)
进行冗余调用。调用不会根据id
参数的变化而变化,因此您只需获取一次,然后在后续调用中从缓存中读取即可。
编辑:concatMap
也是一个选项。它们略有不同。两者都足以满足此答案的目的-我将不对您的用例进行假设。
答案 1 :(得分:1)
首先,应尽可能避免嵌套管道,以便于维护。 而是结合可观察的。
但是对于您的问题:只需删除“ of(ud)”,然后在最后一张地图中返回ud。
可维护性提示:
我看到您有一个电话,不需要按顺序解决。
const userDetails$: Observable<Userdetails> = this.rs.getResults(this.auth.token)
.pipe(map((res: Result[]) => {
const ud: UserDetails = {
user,
results: res.filter(x => x.userId === acc.uid)
};
return ud;
});
const userCheck$: Observable<User> = this.as.getAccount(route.params['id'])
.pipe(map((acc: Account) =>
this.as.getUserDetails(acc.access_token));
// Only when both values are available those observables will be ziped.
// Only one subscription is needed on hte returned Obersvable
return zip(userDetails$,userCheck$).pipe(map(([userDetails,user])) => {
if (user != null) {
return userDetails
}else{
// should probably emit a error
}));