【问题标题】:Angular2 ChangeDetection or Observable?Angular2 ChangeDetection 还是 Observable?
【发布时间】:2016-05-04 10:21:58
【问题描述】:

我在使用登录时不刷新的组件时遇到问题。

该组件是 navbar.component,其中包含指向我的页面/组件的链接。在它上面,有一个“登录”链接呈现 login.component,我可以在上面提供用户名和密码,然后单击登录按钮。 login.component 使用 user.service,它使用 login.component 提供的用户名和密码调用后端,存储接收到的令牌并重定向到'/'。

此时,应该隐藏 navbar.component 上的“登录”链接并显示“注销”链接,但在我单击导航栏上的其他链接之一之前什么都没有发生。

两个链接如下:

<a [hidden]="userService.isLoggedIn" [routerLink]="['Login']">Login</a>
<a [hidden]="!userService.isLoggedIn" (click)="userService.logout();" href="javascript:void(0)">Logout</a>

我了解存储令牌并从 user.service 重定向不会触发更改检测,并且我的属性 userService.isLoggedIn 不是可观察的,所以我知道我遗漏了一些东西,但不确定方法是什么/应该是。

我曾尝试注入 ApplicationRef 来调用 tick() 方法,希望这会触发更改检测,但失败了。

我应该将我的属性 userService.isLoggedIn 设为 observable 吗?

【问题讨论】:

    标签: angular observable angular2-changedetection


    【解决方案1】:
    export class UserService {
      isLoggedIn:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
    }
    
    @Component({
    ...
    template: `
    <a [hidden]="userService.isLoggedIn | async" [routerLink]="['Login']">Login</a>
    <a [hidden]="!(userService.isLoggedIn | async)" (click)="userService.logout();" href="javascript:void(0)">Logout</a>
    `
    
    })
    export class MyComponent {
      constructor(private userService: UserService) {}
    }
    

    【讨论】:

    • 谢谢,但我收到一个错误:[!userService.isLoggedIn | NavbarComponent@4:5] 中的异步 :(
    • 它有效,非常感谢!我这样设置 isLoggedIn 的新值:this.isLoggedIn.next(true);
    • 只是一个简单的问题,什么是 BehaviorSubject?它像基本类型的可观察对象吗?
    • SubjectBehaviorSubject 是创建Observable 的简单方法,其中BehaviorSubject 立即为新订阅者提供最后发出的值。否则,如果订阅了一个主题/可观察对象,则在添加订阅后发出一些新值之前,不会有任何值。传递给new BehaviorSubject()false 是所有订阅者在使用isLoggedIn.emit(someValue) 发出另一个值之前获得的初始值
    【解决方案2】:

    我了解存储令牌并从 user.service 重定向不会触发更改检测

    没错,但如果您使用的是 Angular Http 服务,当从服务返回数据时,更改检测应该在您的回调函数/方法执行后运行。您的导航栏组件是否使用OnPush 更改检测策略? (如果是这样,这就解释了为什么不更新。)

    Günter 的回答有效,因为异步管道不仅会自动将 subscribe()s 发送到可观察对象,而且还会在可观察对象发出新值时调用 markForCheck()。这确保组件(及其所有祖先)将被检测到更改,即使其中任何一个使用OnPush


    仍然使用 BehaviorSubject 的替代方法如下:

    • 将 ChangeDetectorRef 注入您的导航栏组件
    • subscribe() 可观察到的服务
    • 当 observable 触发时,调用 detectChanges()。这将检查组件及其子组件(如果有的话)。这可能比使用 markForCheck() 更有效,尤其是在 NavBar 没有任何子项的情况下。但是考虑到登录/注销可能是罕见的事件,效率可能并不重要。但是,我更喜欢使用detectChanges(),当我只更改视图/组件状态时(就像这里的情况,基于我在下面的实现方式)而不是应用程序状态——即影响多个组件的东西,因此@987654331 @ 会更合适。
    @Component({
      ...
      template: `
        <a [hidden]="userIsLoggedIn" [routerLink]="['Login']">Login</a>
        <a [hidden]="!userILoggedIn" (click)="userService.logout()">Logout</a>
      `
    })
    export class NavBar {
      userIsLoggedIn = false;
      constructor(private userService: UserService, private _ref: ChangeDetectorRef) {}
      ngOnInit() {
         this.userService.isLoggedIn.subscribe( userIsLoggedIn => {
            this.userIsLoggedIn = userIsLoggedIn;
            this._ref.detectChanges();
         });
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-07
      • 2017-01-04
      • 2017-07-26
      • 1970-01-01
      • 2016-06-05
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      相关资源
      最近更新 更多