角度更改检测不适用于 HttpClinet.Subscribe 中的 ChangeDetectionStrategy.OnPush

Pat*_*Pat 7 observable angular2-changedetection angular angular-input

我复制了一个简单的stackblitz,演示了我遇到的问题。问题是我有一个父组件将布尔值传递给子组件。这个布尔值是子组件上的@Input。需要注意的是,父组件使用ChangeDetectionStrategy.OnPush。子组件没有显式设置。

当父组件在订阅方法中更改子组件的布尔输入属性时,子组件最初不会检测到更改。总是需要单击 2 次才能让子组件检测到更改。

但是,当我在订阅方法之外更改子组件的布尔输入属性时,子组件会正确检测到更改,并且一切都会按预期工作(单击 1 次子组件即可识别更改)。

App.Component.ts(父组件)

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent  {
  constructor(private http: HttpClient) {

  }
  public isHelloVisible: boolean;
  public useHttpGet: boolean;

  showHello() {
    if (this.useHttpGet) {
    this.http.get('https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/cc0e3799790b0b34bdeb6fef28c3daf7/17.447409200000003,-78.3724573?units=si').subscribe(data => {
      this.isHelloVisible = true;  
    });
    } else {
      this.isHelloVisible = true;
    }
  }

  closeHello() {
    this.isHelloVisible = false;    
  }
Run Code Online (Sandbox Code Playgroud)

子组件(Hello.component.ts)

@Component({
  selector: 'hello',
  template: `<div *ngIf="showHello">
    Hello
    <div (click)="closeHello()">Click me to close Hello</div>
  </div>
  
  `,
  styles: []
})
export class HelloComponent  {
  @Input() showHello: boolean;
  @Output() close: EventEmitter<any> = new EventEmitter();

  ngOnChanges(changes: SimpleChanges): void {
    console.log(this.showHello);
  }

  closeHello() {
    this.close.emit(null);
  }
Run Code Online (Sandbox Code Playgroud)

如果 useHttpGet 为 true 则不起作用,如果为 false 则一切正常。

我意识到可能有不同的方法来执行此操作或手动触发更改检测,但我更感兴趣的是为什么这不起作用,因为这对我来说没有任何意义。

也许了解其实际效果的最佳方法是关注 stackblitz 演示。

Sla*_*kin 0

如果使用onPush,你应该切换到使用BehaviorSubject,这种情况会发生,因为你的父组件也有onPush,这就是为什么你应该使用Subject或手动调用DetectChanges

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent  {
  constructor(private http: HttpClient) {

  }
  public isHelloVisibleSubject: BehaviorSubject<boolean> = new BehaviorSubject(false);
  public useHttpGet: boolean;

  showHello() {
    if (this.useHttpGet) {
    this.http.get('https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/cc0e3799790b0b34bdeb6fef28c3daf7/17.447409200000003,-78.3724573?units=si').subscribe(data => {
      this.isHelloVisibleSubject.next(true);  
    });
    } else {
      this.isHelloVisibleSubject.next(true);
    }
  }

  closeHello() {
    this.isHelloVisibleSubject.next(false);
  }



<hello [showHello]="isHelloVisibleSubject | async"> </hello

Run Code Online (Sandbox Code Playgroud)