代码之家  ›  专栏  ›  技术社区  ›  Vincent Sels

Ngrx:订阅时主题中未收到当前值

  •  5
  • Vincent Sels  · 技术社区  · 8 年前

    在组件中,我使用存储将主题订阅到我的状态的某个部分。从那时起,当这部分状态发生变化时,我将开始接收更新,我的组件将反映这种状态。到现在为止,一直都还不错。

    然而,我也希望我的组件 初始化 正确地基于 现在的 此状态的值。所以我一订阅,我也想要 要发出的值-因此,例如,我的视图可以正确初始化。

    角度组件示例:

    我的组成部分输电系统

    export class MyComponent implements OnInit {
      constructor(private store: Store<State>) { }
    
      // As soon as I subscribe, I want this to also emit the current
      // value, e.g. so my view can correctly reflect the current state.
      public mode$ = new Subject<ApplicationMode>();
    
      ngOnInit() {
        this.store.select(getApplicationState)
           .select(s => s.applicationMode).subscribe(this.mode$);
      }
    }
    

    我的组成部分html

    {{ mode$ | async }}
    

    我相信我希望/期望的是,我商店的这一部分将返回 BehaviorSubject 或者 ReplaySubject(1) . 但是从商店中选择任何东西都会返回一个 Store<T> 这显然是某种主题,但在订阅时似乎不会产生当前值?

    我想,可行的方法是在应用程序初始化时订阅这段状态,然后将该值传递给它的所有子组件,一直传递到这个组件,这样这个组件就变成了哑组件,而不是从存储本身中进行选择。这可能是要走的路吗?还是说我缺少一些基本的东西来完成这项工作?

    1 回复  |  直到 8 年前
        1
  •  4
  •   bygrace    8 年前

    Ngrx确实像一个行为主体(BehaviorSubject),当您第一次订阅时,您可以获得当前值。

    问题可能是您将价值从行为主体(商店)推到了正常主体( mode$ )在订阅该主题之前。这意味着你将初始值推入你的主题( 模式$ )而且它将没有订户通知,所以它失败了。当订阅者订阅 模式$

    我的建议是去掉中间人,将从商店返回的可见物直接暴露在视图中,如下所示:

    this.mode$ = this.store.select(...);
    

    通过这种方式,您将公开一个可观察对象,该对象将向任何订阅者提供订阅时的当前值。

    我发现很难找到异步管道订阅的组件生命周期中的具体文档。所以我做了一个测试,在每个生命周期钩子中发布到一个主题,并通过异步管道订阅。

    代码:

    import { 
      Component, 
      OnChanges, 
      OnInit, 
      DoCheck, 
      AfterContentInit, 
      AfterContentChecked, 
      AfterViewInit, 
      AfterViewChecked, 
      OnDestroy,
    } from '@angular/core';
    
    import { Subject } from 'rxjs/Subject';
    import 'rxjs/add/operator/do';
    
    @Component({
      selector: 'app-test',
      template: '{{ data$ | async }}'
    })
    export class TestComponent implements 
      OnChanges, 
      OnInit, 
      DoCheck, 
      AfterContentInit, 
      AfterContentChecked, 
      AfterViewInit, 
      AfterViewChecked, 
      OnDestroy {
        public get data$() {
          return this.data.asObservable().do(x => console.log('event: ', x));
        }
        public data: Subject<string> = new Subject<string>();
    
    
      ngOnChanges() {
        this.data.next('ngOnChanges');
      }
    
      ngOnInit() {
        this.data.next('ngOnInit');
      }
    
      ngDoCheck() {
        this.data.next('ngDoCheck');
      }
    
      ngAfterContentInit() {
        this.data.next('ngAfterContentInit');
      } 
    
      ngAfterContentChecked() {
        this.data.next('ngAfterContentChecked');
      }
    
      ngAfterViewInit() {
        this.data.next('ngAfterViewInit');
      }
    
      ngAfterViewChecked() {
        this.data.next('ngAfterViewChecked');
      }
    
      ngOnDestroy() {
        this.data.next('ngOnDestroy');
      }
    }
    

    结果:

    event:  ngAfterViewInit
    event:  ngAfterViewChecked
    event:  ngDoCheck
    event:  ngAfterContentChecked
    event:  ngAfterViewChecked
    

    结果表明,异步管道首先在您第一次订阅的ngOnInit之后执行。这可以解释为什么你错过了它。