在一个组件中,我使用商店订阅了我所在州的某个部分的主题。从那时起,当状态的这一部分发生变化时,我将开始接收更新,我的组件将反映这种状态。到目前为止一切都很好。
但是,我还希望我的组件根据此状态的当前值正确初始化。所以,一旦我订阅,我也希望发出当前值 - 例如,我的视图可以正确初始化。
Angular组件的示例:
my.component.ts
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$);
}
}
my.component.html
{{ mode$ | async }}
我相信我希望/期望的是我商店的这一部分会返回BehaviorSubject
或ReplaySubject(1)
。但是从商店中选择任何东西总是会返回一个Store<T>
,这显然是某种主题,但在订阅时似乎没有发出当前价值?
我想,可能有用的是在应用程序初始化时订阅这个状态,然后通过它的所有子组件传递该值,一直到这个,所以这个组件变成一个愚蠢的而不是从商店本身选择。这可能是要走的路吗?或者是否有一些我缺少的基本工作?
答案 0 :(得分:4)
Ngrx的行为类似于BehaviorSubject,您可以在第一次订阅时获得当前值。
问题可能是您在订阅该主题之前将行为主题(商店)的值推送到正常主题(mode$
)。这意味着您将初始值推送到主题(mode$
),并且没有订阅者通知,因此它会失败。当订阅者订阅mode$
时,它正在订阅正常主题,因此它不会获得当前值,但它将获得所有未来值。
我建议切断中间人并将从商店返回的观察者直接暴露给视图:
this.mode$ = this.store.select(...);
通过这种方式,您将公开一个observable,它将在订阅任何订阅者时提供当前值。
我发现很难找到异步管道订阅的组件生命周期中的具体文档。所以我整理了一个测试,我在每个生命周期钩子中发布一个主题,并通过异步管道订阅它。
代码:
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之后执行。这可以解释为什么你错过了它。