gpt4 book ai didi

Angular2 变更检测误区 - With plunker

转载 作者:太空狗 更新时间:2023-10-29 17:13:08 26 4
gpt4 key购买 nike

我试图完全理解 Angular2 final 的变化检测。

这包括:

  • 处理变更检测策略
  • 从组件上连接和分离更改检测器。

  • 我以为我已经对这些概念有了一个非常清晰的概述,但是为了确保我的假设正确,我写了一个小 plunkr 来测试它们。

    我对全局正确的一般理解,但在某些情况下,我有点迷茫。

    这是plunker: Angular2 Change detection playground

    plunker 快速解释:

    很简单:
  • 一个父组件,您可以在其中编辑一个将传递给两个子组件的属性:
  • 更改检测策略设置为 OnPush 的子级
  • 在更改检测策略设置为默认值的子级上

  • 父属性可以通过以下任一方式传递给子组件:
  • 更改整个属性对象,并创建一个新对象(“ Change obj ”按钮)(触发 OnPush 子项的更改检测)
  • 更改属性对象内的成员(“更改内容” 按钮)(不会触发 OnPush 子项上的更改检测)

  • 对于每个子组件,可以附加或分离 ChangeDetector。 ( "detach()" "reattach()" 按钮)

    OnPush 子级有一个额外的内部属性可以编辑,
    并且可以显式应用更改检测( "detectChanges()" 按钮)

    以下是我无法解释的行为的场景:

    场景1:
  • 分离 OnPush 子项和默认子项的更改检测器(在两个组件上单击“ detach() ”)
  • 编辑父属性名字和姓氏
  • 点击“更改对象”将修改后的属性传递给 child

  • 预期行为:
    我期待 两者 children 不要被更新,因为他们都分离了他们的变化检测器。

    当前行为:
    默认子级未更新,但 OnPush 子级已更新.. 为什么?
    它不应该是因为它的CD是分离的......

    场景2:
  • 分离 OnPush 组件的 CD
  • 编辑它的 内部值 输入并点击 更改内部 : 什么都没有发生,因为CD是分离的,所以没有检测到变化... OK
  • 点击检测变化() :检测到更改并更新 View 。到现在为止还挺好。
  • 再次编辑 内部值 输入并点击 更改内部 : 再次,没有任何 react ,因为CD被分离,所以没有检测到变化.. OK
  • 编辑父属性名字和姓氏。
  • 点击“更改对象”将修改后的属性传递给 child

  • 预期行为:
    OnPush 子项根本不应该更新,再次因为它的 CD 是分离的...... CD 根本不应该发生在这个组件上

    当前行为:
    值和内部值都被更新,像完整的 CD 一样的接缝被应用到这个组件上。
  • 最后一次编辑 内部值 输入并点击 更改内部 : 检测到更改,并更新内部值...

  • 预期行为:
    不应更新内部值,因为 CD 仍处于分离状态

    当前行为:
    检测到内部值更改... 为什么?

    结论:

    根据这些测试,我得出以下结论,这对我来说很奇怪:
  • 带有 OnPush 策略的组件获取 '检测到更改'当他们的输入改变时,即使他们的变化检测器是分离的。
  • 每次输入更改时,具有 OnPush 策略的组件都会重新连接更改检测器...

  • 你如何看待这些结论?

    你能用更好的方式解释这种行为吗?

    这是错误还是所需的行为?

    最佳答案

    更新

    Component with OnPush strategy get 'changed detected' when their input changes, EVEN IF their change detector is detached.



    Angular 4.1.1 (2017-05-04) OnPush应该尊重 detach()
    https://github.com/angular/angular/commit/acf83b9

    旧版本

    关于变更检测的工作原理,有很多未记录的内容。

    我们应该注意三个主要的 更改检测状态 ( cdMode ):

    1) CheckOnce - 0

    CheckedOnce means that after calling detectChanges the mode of the change detector will become Checked.



    AppView 类
    detectChanges(throwOnChange: boolean): void {
    ...
    this.detectChangesInternal(throwOnChange);
    if (this.cdMode === ChangeDetectorStatus.CheckOnce) {
    this.cdMode = ChangeDetectorStatus.Checked; // <== this line
    }
    ...
    }

    2) 已检查 - 1

    Checked means that the change detector should be skipped until its mode changes to CheckOnce.



    3) 独立式 - 3

    Detached means that the change detector sub tree is not a part of the main tree and should be skipped.



    这里是 Detached的地方用来

    AppView 类

    跳过内容检查
    detectContentChildrenChanges(throwOnChange: boolean) {
    for (var i = 0; i < this.contentChildren.length; ++i) {
    var child = this.contentChildren[i];
    if (child.cdMode === ChangeDetectorStatus.Detached) continue; // <== this line
    child.detectChanges(throwOnChange);
    }
    }

    跳过 View 检查
    detectViewChildrenChanges(throwOnChange: boolean) {
    for (var i = 0; i < this.viewChildren.length; ++i) {
    var child = this.viewChildren[i];
    if (child.cdMode === ChangeDetectorStatus.Detached) continue; // <== this line
    child.detectChanges(throwOnChange);
    }
    }

    跳过更改 cdModeCheckOnce
    markPathToRootAsCheckOnce(): void {
    let c: AppView<any> = this;
    while (isPresent(c) && c.cdMode !== ChangeDetectorStatus.Detached) { // <== this line
    if (c.cdMode === ChangeDetectorStatus.Checked) {
    c.cdMode = ChangeDetectorStatus.CheckOnce;
    }
    let parentEl =
    c.type === ViewType.COMPONENT ? c.declarationAppElement : c.viewContainerElement;
    c = isPresent(parentEl) ? parentEl.parentView : null;
    }
    }

    注: markPathToRootAsCheckOnce正在您 View 的所有事件处理程序中运行:

    enter image description here

    因此,如果将状态设置为 Detached那么你的观点就不会改变。

    那么如何运作 OnPush策略

    OnPush means that the change detector's mode will be set to CheckOnce during hydration.



    编译器/src/view_compiler/property_binder.ts
    const directiveDetectChangesStmt = isOnPushComp ?
    new o.IfStmt(directiveDetectChangesExpr, [compileElement.appElement.prop('componentView')
    .callMethod('markAsCheckOnce', [])
    .toStmt()]) : directiveDetectChangesExpr.toStmt();

    https://github.com/angular/angular/blob/2.1.2/modules/%40angular/compiler/src/view_compiler/property_binder.ts#L193-L197

    让我们看看它在您的示例中的外观:

    父工厂(AppComponent)

    Enter image description here

    再次回到 AppView 类 :
    markAsCheckOnce(): void { this.cdMode = ChangeDetectorStatus.CheckOnce; }

    场景一

    1) Detach Change detector of OnPush Children and Default Children (click "detach()" on both components)


    OnPush.cdMode - Detached

    3) Click "Change obj" to pass the modified attribute to the children


    AppComponent.detectChanges
    ||
    \/
    //if (self._OnPush_35_4.detectChangesInInputProps(self,self._el_35,throwOnChange)) {
    // self._appEl_35.componentView.markAsCheckOnce();
    //}
    OnPush.markAsCheckOnce
    ||
    \/
    OnPush.cdMode - CheckOnce
    ||
    \/
    OnPush.detectChanges
    ||
    \/
    OnPush.cdMode - Checked

    因此 OnPush.dectectChanges正在开火。

    这是结论:

    Component with OnPush strategy get 'changed detected' when their input changes, EVEN IF their change detector is detached. Moreover It changes view's status to CheckOnce.



    场景2

    1) Detach CD for the OnPush component


    OnPush.cdMode - Detached

    6) Click "Change obj" to pass the modified attribute to the children


    See 3) from scenario 1 => OnPush.cdMode - Checked

    7) For the last time, edit the internal value input and click change internal: Change is detected, and internal value is updated ...



    正如我上面提到的,所有事件处理程序都包括 markPathToRootAsCheckOnce .所以:
    markPathToRootAsCheckOnce
    ||
    \/
    OnPush.cdMode - CheckOnce
    ||
    \/
    OnPush.detectChanges
    ||
    \/
    OnPush.cdMode - Checked

    正如您所看到的 OnPush 策略和 ChangeDetector 管理一个属性 - cdMode

    Component with OnPush strategy get their change detector re attached each time their input changed ...



    总之,我想说,看来你是对的。

    关于Angular2 变更检测误区 - With plunker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40331923/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com