Angular onPush不会从父级更新子属性 [英] Angular onPush does not update child property from parent

查看:199
本文介绍了Angular onPush不会从父级更新子属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个看起来像这样的子组件:

I have a child component that looks like this:

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

  constructor(public host: ElementRef) { }
}

以及如下所示的父组件:

And a parent component that looks like this:

@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 属性时,没有任何事情发生。

The first assign to the text property is working fine, but when I click the button and try to change the text property again nothing is happening.

这让我感到困惑,因为据我所知:
1.点击事件应触发变更检测,文本属性不同,因此应该更新。
2.我明确地调用了 detectChanges(),这也应该检查我所知道的孩子。

That's confusing because from what I know: 1. The click event should trigger change detection and the text property is different so it should have been updated. 2. I explicitly called detectChanges() and this should check also the children from what I know.

我错过了什么?

推荐答案

问题与此问题在GitHub上报道。它发生在:

The problem is related to this issue reported on GitHub. It occurs when:


  • OnPush 更改检测策略用于子组件

  • 子组件的输入属性直接在父组件代码中更改,而不是在父组件模板中进行数据绑定

  • The OnPush change detection strategy is used for the child component
  • An input property of the child is changed directly in the parent component code instead of being data-bound in the parent component template

AngularInDepth.com 给出的解释:


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

The compiler doesn't have a way to generate necessary information for checking the bindings since it can't find these bindings in the template. OnPush is tightly bound to the input bindings. What's important is that Angular checks the second part of the binding (prop in the example below), not the first (i):

<child [i]="prop">

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

to determine whether the change detection should be run for the child component. And it does so when checking parent component. If you don't show the compiler what parent property should be used to update child input binding, it can't generate necessary information used when checking the parent. So inspecting @Input on child components isn't enough. That's the mechanism of change detection and I don't see any way it could be changed.

建议的一个解决方法讨论中 yurzui 是在孩子中调用 ChangeDetectorRef.markForCheck 设置 text 属性后的组件,如 此stackblitz 。事实上,它可以在父组件中调用 ChangeDetectorRef.detectChanges

One workaround suggested by yurzui in the discussion is to call ChangeDetectorRef.markForCheck in the child component after setting the text property, as shown in this stackblitz. As a matter of fact, it works without calling ChangeDetectorRef.detectChanges in the parent component.

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) { }
}

这篇关于Angular onPush不会从父级更新子属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆