【问题标题】:Angular onPush does not update child property from parentAngular onPush 不会从父级更新子属性
【发布时间】:2018-09-26 15:54:30
【问题描述】:

我有一个如下所示的子组件:

@Component({
  selector: 'app-child',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    {{text}}
  `
})
export class ChildComponent {
  @Input() text = '';

  constructor(public host: ElementRef) { }
}

还有一个看起来像这样的父组件:

@Component({
  selector: 'app-parent',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<ng-content></ng-content>`
})
export class ParentComponent {
  @ContentChild(ChildComponent) child: ChildComponent;

  constructor(private cdr: ChangeDetectorRef) { }

  ngAfterContentInit() {
    this.child.text = 'hello';
    this.child.host.nativeElement.addEventListener('click', () => {
      this.child.text = 'from click';
      this.cdr.detectChanges();
    });
  }

第一次分配给text 属性工作正常,但是当我单击按钮并尝试再次更改text 属性时,什么也没有发生。

这很令人困惑,因为据我所知: 1. click 事件应该触发变化检测,并且 text 属性不同,所以应该已经更新了。 2. 我明确地调用了detectChanges(),这也应该检查我所知道的孩子。

我错过了什么?

【问题讨论】:

  • 我不确定,但由于text@Input 属性,Angular 可能希望您将此值从父级传递给子级,而不是直接从父级修改它。
  • 不要认为这是问题所在,因为第一次调用是有效的。
  • 是的,但变更检测的第一次运行往往是边缘情况或规则的例外,但让我们看看是否有人可以更深入地解释这一点。

标签: javascript angular


【解决方案1】:

该问题与 GitHub 上报告的this issue 有关。它发生在:

  • 子组件使用OnPush变化检测策略
  • 子组件的输入属性直接在父组件代码中更改,而不是在父组件模板中进行数据绑定

AngularInDepth.com给出的解释:

编译器无法生成检查所需的信息 绑定,因为它在模板中找不到这些绑定。 OnPush 与输入绑定紧密绑定。重要的是 Angular 检查绑定的第二部分(道具在 下面的例子),而不是第一个(i):

<child [i]="prop">

确定是否应该为孩子运行更改检测 零件。它在检查父组件时这样做。如果你不 向编译器显示应该使用什么父属性来更新子属性 输入绑定,它不能生成使用时使用的必要信息 检查父母。所以检查子组件上的@Input 不是 足够的。那是变化检测的机制,我没有看到任何 可以改变它的方式。

yurzui在讨论中建议的一种解决方法是在设置text属性后在子组件中调用ChangeDetectorRef.markForCheck,如this stackblitz所示。事实上,它不需要在父组件中调用ChangeDetectorRef.detectChanges

export class ChildComponent {

  private _text = '';

  @Input()
  get text() {
    return this._text;
  }
  set text(val) {
    if (this._text !== val) {
      this.cdRef.markForCheck();
    }
    this._text = val;
  }

  constructor(public host: ElementRef, private cdRef: ChangeDetectorRef) { }
}

【讨论】:

  • 为什么我需要调用 markForCheck 而不是 detectChanges?
  • 查看this answer 和同一问题中的其他问题。我的理解是,更改检测是由单击事件触发的,但子级的 text 属性不包含在其中(因为 OnPush 策略),除非您明确调用 markForCheck
猜你喜欢
  • 2011-07-03
  • 2018-01-15
  • 2020-02-07
  • 1970-01-01
  • 2017-05-18
  • 2019-03-15
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
相关资源
最近更新 更多