为什么异步管道检测不到 Angular 中的更改(但 component.ts 中的订阅检测到)?

Why doesn't async pipe detect changes in Angular (but subscription in component.ts does)?

我在 angular 中使用异步管道来监视来自 rxjs 存储的可观察对象。组件的 ngOnInit 看起来像这样

ngOnInit() {
  this.userRole$ = this.store.select(selectUserProfile).pipe(
    filter(user => !!user),
    map(user => parseUserRole(user.role))
  );
}

组件模板如下所示

<p> User role is {{ userRole$ | async }} </p>

用户登录后,页面上的消息仍然是一个空字符串

在component.ts我添加了以下代码来调试问题

this.userRole$.subscribe(userRole => {
  alert(`new user role is ${userRole}`);
});

用户登录后,我收到一条提示 "new user role is admin",但是 html 模板中的管道没有更新。

当我使用 of() 将商店 select() 替换为虚拟值时,一切都按预期工作,所以我很确定问题与 rxjs 有关。

auth reducer(正在启动)看起来像这样(

export function reducer(state = initialAuthState, action: AuthActions): AuthState {
    switch (action.type) {
        /// ...CODE OMITTED
        case AuthActionTypes.UserProfileRetrieved:
            alert(`setting user profile ${action.payload.userProfile}`)
            return { ...state, userProfile: action.payload.userProfile }
        default:
            return state;
    }
}

我已尝试确保从 ngZone.run() 内部调度 UserProfileRetrieved 操作,但这并没有什么区别。我真的不知道如何调试它。任何指针将不胜感激。谢谢!

你能试试这个代码,看看它是否工作正常。添加了 tap 运算符以查看是否发生了从商店发出的 changes/data。

this.userRole$ = this.store
   .select(selectUserProfile)
   .pipe(
     tap(user => console.log('FETCHED:', user)),        // Console if user data exists
     filter(Boolean),                                   // Change !!user to Boolean
     tap(user => console.log('FILTERED:', user)),       // Console if user exists after filter 
     map(user => parseUserRole(user.role))
     tap(user => console.log('MAPPED:', user)),         // Console if user is mapped
   );

NOTE:

That the store will only send it's response once the prior/parent service is invoked.

示例:

// If along with the getUsers() functionality has a piped storeService in it
// http.get(url).pipe(tap(data => this.storeService.set('users', data)))
this.userService.getUsers().subscribe();    

// You can then initialize your store to get the data invoked/set above
this.user$ = this.store.select('users');

这原来是由 auth0 本机应用程序登录流程的副作用引起的。应用路由器配置为使用基于哈希的路由以支持 Cordova。从 auth0 获取登录令牌后,我们正在清除哈希以删除令牌信息。在此之后的任何商店更新都不会反映在异步管道中,但在此之前的更新。

如果有人遇到类似问题,请确保在导航到 post 授权 URL 之前,清除哈希是您做的最后一件事。感谢@Shorbag​​y 和@KShewengger 的帮助。

这是我用来执行此操作的代码

@Effect()
    loginComplete$ = this.actions$.pipe(
        ofType<LoginComplete>(AuthActionTypes.LoginComplete),
        exhaustMap(() => {
            return this.authService.authResult$.pipe(
                map((authResult: any) => {
                    if (environment.platform.name === Platforms.BROWSER) {
                        window.location.hash = '';
                    }

                    if (authResult && authResult.accessToken) {
                        this.authService.setAuth(authResult);
                        return new LoginSuccess();
                    } else {
                        debugger;
                        return new LoginFailure({ message: 'no accessToken', payload: authResult })
                    }
                }),
                catchError(error => of(new LoginFailure(error)))
            );
        })
    );