使用Angular的ChangeDetectionStrategy.OnPush
,我尽量使用Async-Pipe/订阅可观察对象,只要我可以-对吧?所以不像{{value}}
那样绑定到我的值,我宁愿使用{{valueChange | async}}
,它工作得很好,除了初始值。我认为事件是在模板加载之前触发的,所以它没有得到初始值:
https://stackblitz.com/edit/angular-b9wbvu
解决这个问题的最佳实践是什么?还是我对ChangeDetectionStrategy.OnPush
的理解有误?
正如上面@M1CH3L1US所提到的,这不是关于changeDetectionStrategy的问题。changeDetectionStrategy影响如何触发变更检测。对于这个线程中的各种changeDetectionStrategy有多种解释。
什么是ChangeDetectionStrategy在Angular2和何时使用OnPush Vs默认?
关于你的问题,有一些解决办法
- 使用一个不同的Angular生命周期钩子来触发你的初始值,比如AfterViewInit就可以了
export class AppComponent implements OnInit, AfterViewInit {
name = 'Angular';
setRandomValue(): void {
this.value = new Date().toString();
}
ngOnInit(): void {
}
ngAfterViewInit(){
this.setRandomValue();
}
@Input() set value(v: string) {
this._value = v;
this.valueChange.emit(this._value);
}
@Output() valueChange = new EventEmitter<string>();
public _value: string;
}
- 使用行为主题
这个方法将允许你的Observable实际存储一个值,防止任何竞争条件。
export class AppComponent implements OnInit, AfterViewInit {
name = 'Angular';
value$ = new BehaviorSubject(null);
setRandomValue(): void {
const newValue = new Date().toString()
this.value$.next( newValue )
this.value = newValue
}
ngOnInit(): void {
this.setRandomValue();
}
ngAfterViewInit(){
}
@Input() set value(v: string) {
this._value = v;
this.valueChange.emit(this._value);
}
@Output() valueChange = new EventEmitter<string>();
public _value: string;
}
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<p>
Current Value non async: {{_value}}
</p>
<p>
Current Value: {{value$ | async}}
</p>
<p>
<button (click)="setRandomValue()">ChangeValue</button>
</p>
- 最后,你必须问自己是否需要异步值?如果这个值是通过@Input传入的,就像你的例子一样,你总是会得到传递给组件的实际值。因此,您可能不需要额外的复杂性
当你订阅EventEmitter
(或者更确切地说,Angular通过async管道订阅它)的时候,ngOnInit
中的代码已经运行了。EventEmitter
扩展了一个不保存最近状态值的Subject。通过在第一个值已经发出之后订阅它,您将不会被第一个值通知。我建议你把启动代码移到ngAfterViewInit
中,这将使初始化在视图被渲染后运行,并且事件发射器的订阅已经被Angular绑定了。
注:我只是注意到,改变ngAfterViewInit
的值将不是最佳的,因为这将改变组件状态后,视图已被检查。为了确保你在保存端,我建议你在设置完组件状态后让Angular再次运行变更检测:
class AppComponent implements AfterViewInit {
constructor(private readonly cdRef: ChangeDetectorRef) { }
ngAfterViewInit(): void {
this.setRandomValue();
this.cdRef.detectChanges();
}
}
ChangeDetectionStrategy
在这里与它无关,因为Angular无法知道状态的变化。
希望这是有意义的:3