angular - 尽管有 OnPush 策略,为什么 Angular 会在 DOM 事件的父组件上触发 ChangeDetection?

标签 angular angular-changedetection

技巧问题我还没有在文档中找到任何答案。

AppRef.tick() 被调用时(主要是通过 NgZone 补丁),一个变化检测周期被触发。它从树顶部的根组件到底部经过:

  • 具有默认策略的每个组件
  • 每个由 markForCheck 标记的组件(及其祖先)

并跳过未标记的 OnPush 组件。

但是为什么当一个事件被一个组件触发时,它的所有祖先也会被检查?就像调用了 markForCheck 一样。

我期待与调用 AppRef.tick 时相同的行为。我不明白为什么要检查 OnPush parent 。在 this demo 上可以很好地看到这种行为.

另请参阅 working illustration on stackblitz

最佳答案

也许你对OnPush的误解和我刚开始学习变化检测的时候一样:)。重点是:OnPush 策略不会改变任何关于触发 CD 周期的事件。这只是taken care of by zone.js by patching browser APIs . (除非手动触发 CD。)zone.js 不关心组件和 ChangeDetectionStrategies。并且 CD 总是从根目录开始为 @Chris Hamilton解释。

ChangeDetectionStrategy.Default 和 OnPush 的区别仅在于组件将在 CD 周期中实际被检查。

所以你原帖中的句子应该是: “已知 OnPush 策略仅在以下情况下标记要检查的组件”。

下面是我使用 Angular DevTools 的分析器观察到的示例.我在OnPush组件的ngOnInit中放了一个setTimeout(() => {}, 6000),它触发了一个CD循环(来源是“setTimeout”),但是并没有引起组件本身进行检查。

enter image description here

关于手动触发的detectChanges()、tick()和markForCheck()的区别:

  • ChangeDetectorReference.detectChanges() 通过尊重子组件的 CD 策略在此组件及其子组件上触发 CD
  • ApplicationRef.tick() 通过遵守 CD 策略为整个应用程序触发 CD
  • ChangeDetectorReference.markForCheck() 不会触发 CD,但会将所有 OnPush parents 标记为在当前或下一个 CD 周期中检查一次

(解释得很好 here )

=== 编辑:更新问题的答案===

如果浏览器事件监听器在 OnPush 组件中被触发,这将导致 OnPush 组件被标记为检查。此外,它还会触发从组件根部开始的更改检测。

如果我理解正确的话,你的问题是:为什么 OnPush 组件的所有父组件也必须标记为检查?

回答:如果一个OnPush组件没有被标记为check,那么不仅这个组件会被跳过,这个组件下面的整个子树也会被跳过。这意味着,如果事件处理程序被触发的组件有一个带有 OnPush 的父组件不会被检查,它本身也不会被检查。或者,反过来说,如果要检查一个组件,则还必须检查它的所有祖先。

关于angular - 尽管有 OnPush 策略,为什么 Angular 会在 DOM 事件的父组件上触发 ChangeDetection?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71945490/

相关文章:

angular - 如何手动触发事件并进行变更检测?

使用函数调用多次的 Angular @Input 绑定(bind)

javascript - Angular 2 单例列表多窗口数据共享

html - 在 mat-card-title 中左右对齐

css - Angular 6 Material - 色调以及如何更改垫子单选按钮的颜色

angular - 如何在从父组件中的 ajax 调用接收数据后更新子组件

angular - 嵌入式与 ng-content 子级的不同 ChangeDetectionStrategy.OnPush 行为

angular - 在自定义 TG2480H 打印机上打印 Logo

javascript - 在 json 对象数组中查找一个键值,并使用 Angular 返回另一个键值

使用模板内的 getter 触发的 Angular 变化检测循环