ChangeDetectionStrategy.OnPush 的行为不符合我的预期

2024-02-10

我正在尝试熟悉 Angular 2ChangeDetectionStrategy.OnPush性能提升(如所解释的here https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html)。但我这里有一个奇怪的案例。

我有父母AppComponent:

@Component({
  selector: 'my-app',
  template: `<h1>
  <app-literals [title]="title" [dTitle]="dTitle"></app-literals>
  <input [value]="title.name"/>
</h1>
`
})
export class AppComponent implements OnInit {
  title = { name: 'original' };
  dTitle = { name: "original" };

  constructor(private changeDetectorRef : ChangeDetectorRef) {

  }

    ngOnInit(): void {
      setTimeout(() => {
        alert("About to change");
        this.title.name = "changed";
        this.dTitle = { name: "changed" };
      }, 1000);
    }

}

还有孩子LiteralsComponent成分:

@Component({
  selector: 'app-literals',
  template: `  {{title.name}}
  {{dTitle.name}}`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class LiteralsComponent implements OnInit {
  @Input('title') title;
  @Input('dTitle') dTitle;

  constructor() { }

  ngOnInit() {
  }

}

我认为制定策略OnPush使角度仅反映引用的变化,但在示例中我尝试更改(变异)对象的属性,角度仍然反映它。

this.title.name = "changed";不应被检测到(因此 UI 不应反映更改)。

这是关于的案例plunker https://plnkr.co/edit/zjgnXVJIg0m3Zb1EBYcX?p=preview

怎么会?怎样做才正确呢?


如果我理解正确的话,您会问为什么绑定值会在LiteralsComponent即使您不修改参考模板title,而是改变对象。

简短的回答是因为你修改了两者:

this.title.name = "changed";
this.dTitle = {name: "changed"};

in the AppComponent.ngOnInit。如果只修改this.title.name = "changed"您将看到该模板未更新。

然而,这是一个非常有趣的问题,需要详细探讨

我们首先只从this.title没有this.dTitle.
首先要了解的是,当您在模板中指定以下内容时:

{{title.name}}

这就是 Angular 所做的。它试图找到title当前组件实例上的对象,然后获取name来自它的属性并将其反映在 DOM 中。但具有以下配置:

class AppComponent {
    title = { name: 'original' }

    ngOnInit(): void {
      setTimeout(() => {
        alert("About to change");
       this.title.name = "changed";
    }, 1000);
}
}

class LiteralsComponent {
     @Input() title;
}

the title对象是the same在两个组件中(指向相同的内存位置)。

因此,当 Angular 运行更改检测时LiteralsComponent组件,它访问您在此处更改的同一对象AppComponent:

ngOnInit(): void {
  setTimeout(() => {
    alert("About to change");
    this.title.name = "changed";
  }, 1000);
}

这里有趣的观察是变化未检测到根本不与OnPush也没有它:

class LiteralsComponent {
     @Input() title;

     ngOnChanges(changes) {
         // will be triggered only for the first CD cycle,
         // and won't be triggered when `title` is updated
     }
}

现在,最后一件事是要了解 DOM 何时更新。根据本文 https://hackernoon.com/everything-you-need-to-know-about-change-detection-in-angular-8006c51d206f,它会在当前组件的 CD 期间更新。这意味着如果当前组件没有被检查,DOM将不会被更新。所以我们指定onPush为了LiteralsComponent:

changeDetection: ChangeDetectionStrategy.OnPush,

视图不会更新。

但是,它已在您的问题中更新。为什么?

还有这个地方dTitle开始发挥作用。使用此属性,您实际上是在修改参考和 Angular检测绑定变化并运行 CDLiteralsComponent成分。上面我们了解到,当 CD 运行时,DOM 会更新。所以 Angular 也更新了{{title.name}}因为它指向同一个对象AppComponent, 虽然它没有检测到它被改变了.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ChangeDetectionStrategy.OnPush 的行为不符合我的预期 的相关文章

  • Angular 7 Guard 重定向仅适用于双击

    问题是我已经实现了一个 Guard 旨在处理特定的目录 如果当前用户名的角色等于 2 它应该返回 true 如果没有 那么它不应该重定向 这是我的 app routing module ts 文件 问题出在 userlist 路径中 我们是
  • Angular + Material - 如何使用 formgroup 处理多个复选框

    我有一个从后端获得的兴趣列表 我希望用户能够选择他们想要的兴趣 我将只存储他们在数据库中检查的兴趣 并在他们加载页面时预先填充 但首先我需要获取用户选择的这些兴趣 兴趣组件 ts export class InterestsComponen
  • 如何将数组数据作为formdata Angular 4发送

    我尝试发布一组数据未发送到服务器 网络服务 deleteCategory return this http post http www demo webapi deletecategory headers Authorization Tok
  • Angular 反应式表单:使用单个 formControlName 同步多个输入

    我正在建造一个反应形式 https angular io guide reactive forms在 Angular 11 中 它分为多个 div 项目所有者希望在每个 div 中进行一些重复输入 以便用户可以编辑某个字段 A 的输入 并且
  • Angular 7 向原语添加扩展方法

    我想向原语添加一些方法 我有以下文件 字符串扩展 ts interface String isNullOrEmpty this string boolean String prototype isNullOrEmpty function t
  • Angular 5,如何检测用户不活动

    除了使用 IdleJS 和 ngDoCheck 之外 我们如何在 Angular 5 中检测用户的不活动状态 Thanks 你可以尝试用这个 export class AppComponent userActivity userInacti
  • Gulp 和 TS 编译

    我在我的 gulp 文件中定义了任务 gulp task dev build scripts function var tsResult tsProject src pipe sourcemaps init pipe ts tsProjec
  • 如何通过 JS 中的 WebPack 包提供全局 TypeScript 类

    我目前正在研究 TypeScript 我想用 TS 替换 JS 但是我有很多 JS 文件 所以我只想在 TS 中创建新类 并想在我的旧 JS 文件 atm 中使用这些类 后来我想把所有的JS都换成TS 我对 webpack 和捆绑的 js
  • 从 firestore 返回嵌套集合作为 angularfire2 和 firebase 的对象

    假设您有以下结构 shopping carts collection shopping cart 1 doc dateCreated field items collection shopping cart 2 doc dateCreate
  • 为什么抽象类必须实现接口中的所有方法?

    interface BaseInter name string test void abstract class Abs implements BaseInter 在 TypeScript 中 编译器抱怨该类错误地实现了接口 Abs 类型中
  • Angular 2延迟加载模块-服务不是单例

    我已经在我的应用程序中实现了延迟加载模块 app module ts 配置正确 NgModule declarations AppComponent HeaderComponent HomeComponent imports Browser
  • TypeScript 中的“环境”是什么意思

    我不明白这个词是什么意思ambient在下面的句子中 不能在环境上下文中声明函数实现 我不确定是否理解这个词的一般含义 英语不是我的母语 如果这里有什么具体含义 我也不明白 我试图用我的母语来理解 但在这种情况下无法理解 这就像curren
  • Angular 中的动态子组件

    我正在构建一个具有一致的元素列表设计模式的应用程序 如果我有一个 A 类型的对象 我会创建AComponent它接受a作为输入 然后创建另一个组件来迭代 A 列表 AListComponent 那么如果我有一个对象 B 我需要做同样的事情
  • Typescript 继承:扩展基类对象属性

    当扩展一个类时 我可以轻松地向它添加一些新属性 但是 如果当我扩展基类时 我想向基类的对象 简单对象的属性 添加新属性怎么办 这是一个带有一些代码的示例 基类 type HumanOptions alive boolean age numb
  • For-each 在 ionic2 和 angularjs2 中

    我用 IONIC 2 Beta 版本制作了一个应用程序 我想用for each环形 是否可以在 Angular V2 中使用每个 Thanks 首先在Component 您必须声明要显示的数组 import Component from a
  • 如何在 Angular4 中上传相同的文件

    我能够成功上传文件 但现在的问题是它不允许我两次上传同一文件 这是我的代码
  • 角度分割列表

    我有一个看起来像这样的列表 A B C 是否有任何简单的方法 而无需创建一个函数 将其展平为一个看起来像这样的数组 A B C 我搜索了 SO 但没有找到任何带有打字稿方法的内容 Thanks 编辑 A B C 是相同类型 看来您正在寻找的
  • Visual Studio 2015/2017 中的 TSLint?

    我的组织使用TSLint https github com palantir tslint 我们非常重视 Typescript 代码的质量检查 它为我们提供了有价值的服务 然而 我们使用 Visual Studio 2015 和 2017
  • 如何重启ngOnInit来更新Interpolation

    有办法重新启动吗ngOnInit 改变变量时 因为我想重新开始ngOnInit 改变时theme多变的 这是我的代码 设置 ts export class SettingsPage implements OnInit phraseColor
  • 根据唯一测试提取站点地图 URL 和 cy.request() 每个 URL (Cypress) [重复]

    这个问题在这里已经有答案了 将 Cypress 与 TypeScript 结合使用 我的代码目标是提取 sitemap xml 中的所有 URL 和 cy request 每个 URL 的状态 200 这个版本的工作原理 describe

随机推荐

  • NLTK python 错误:“TypeError:‘dict_keys’对象不可下标”

    我正在按照课堂作业的说明进行操作 并且应该在文本文件中查找最常用的 200 个单词 这是代码的最后一部分 fdist1 FreqDist NSmyText vocab fdist1 keys vocab 200 但是当我在 vocab 20
  • Pickle:类型错误:需要类似字节的对象,而不是“str”[重复]

    这个问题在这里已经有答案了 当我在 python 3 中运行以下代码时 我不断收到此错误 fname1 auth cache s username fname fname1 encode encoding utf 8 fname fname
  • 自定义图像视图android

    我的自定义视图如下所示 package com mypackage import java util ArrayList import java util List import android content Context import
  • 以数组形式返回 group_concat 数据

    我想返回使用 group concat 作为数据数组从数据库检索的值 是否可以在 mysql 查询中执行此操作 或者我需要将数据分解成数组吗 GROUP CONCAT sh hold id as holds 返回这个 holds gt 3
  • 为什么从对象继承在 Python 中会有所不同? [复制]

    这个问题在这里已经有答案了 当类从无继承时 我有一个实例类型的对象 gt gt gt class A pass gt gt gt a A gt gt gt type a
  • 将 AVAssetWriter 与原始 NAL 单元结合使用

    我在 iOS 文档中注意到AVAssetWriterInput你可以通过nil为了outputSettings字典来指定输入数据不应重新编码 用于对附加到输出的媒体进行编码的设置 传递 nil 来指定不应重新编码附加的样本 我想利用此功能来
  • 如何为TableView创建NSIndexPath

    我需要在我定义的函数中删除表的第 1 行 为了使用deleteRowAtIndexPath你必须使用一个IndexPath定义了部分和行 如何创建这样的索引路径 以 int 1 作为唯一成员的数组将会崩溃 NSLog 消息指出该部分也需要定
  • pandas 按日期和年份分组并汇总金额

    我有这样的熊猫数据框 d dollar amount 200 25 350 00 120 00 400 50 1231 25 700 00 350 00 200 25 2340 00 date 22 01 2010 22 01 2010 2
  • 调试时如何跳出while循环

    在 Eclipse 中调试期间 我的代码进入了 while 循环 我不想循环直到满足条件 所以请告诉我如何在调试期间退出 while 循环 我看到 F7 在调试菜单下被禁用 请参阅此处的屏幕截图 You can select the lin
  • javascript 函数 btoa 的 C# 版本

    我需要将一些内容从 js 重新编码为 c 利用 js 中的 btoa 方法对一串 unicode 字符将它们转换为 base64 但是 据我所知 javascrpt 使用的编码与 c 中可用的所有编码不同 我需要编码完全相同 并且不会在这些
  • 如何在perl中验证数字?

    我知道有一个图书馆可以做到这一点 使用 Scalar Util qw looks like number 但我想使用 perl 正则表达式来做到这一点 我希望它适用于双数 而不仅仅是整数 所以我想要比这更好的东西 var d thanks
  • 从 OKHTTP 下载二进制文件

    我在我的 Android 应用程序中使用 OKHTTP 客户端进行网络连接 This https stackoverflow com questions 25367888 upload binary file with okhttp fro
  • Xpath获取上面的元素

    假设我有这样的结构 div class a div class b span Text Example span div div 在 xpath 中 我想检索属性 attribute 的值 因为我里面有文本 文本示例 如果我使用这个 xpa
  • 如何在VBA中实现消失动画?

    我正在尝试在 VBA 过程中测试形状上的动画效果 我已经实现了一个目标 即在主序列 定义在哪个位置Timeline 但我无法创建消失的动画 我在代码的开头检查了一些已经存在的 并且 EffectType 似乎返回与相关出现的动画相同的值 因
  • 实现永不过期的 OAuth 刷新令牌

    在 OAuth 2 的上下文中 如何处理refresh token过期 还是缺少 我使用 JSON Web 令牌 JWT 作为access token生命周期较短 20 分钟后过期 据我了解 这意味着我不必存储access token 仅验
  • 带标头的 post 请求中出现错误 411(需要长度),但标头具有 Content-Length。库卷曲

    我使用这个选项 curl easy setopt curl CURLOPT URL urlUpload curl easy setopt curl CURLOPT ERRORBUFFER errorBuffer curl easy seto
  • SQLite 自动增量不起作用

    好吧 这不是垃圾邮件 它应该很简单 我不知道为什么它不起作用 这是我的代码 gamesdatabase openOrCreateDatabase GamesDatabase MODE PRIVATE null gamesdatabase e
  • 获取数组中的所有非唯一值(即:重复/多次出现)

    我需要检查 JavaScript 数组以查看是否存在重复值 做到这一点最简单的方法是什么 我只需要找到重复的值是什么 我实际上不需要它们的索引或它们重复了多少次 我知道我可以循环遍历数组并检查所有其他值是否匹配 但似乎应该有一种更简单的方法
  • 保存和加载数据“MVVM”方式?

    我目前正在使用 Telerik 提供的一些控件开发一个 C WPF 项目 并且我尊重 MVVM 模式 包含数据的模型 将数据呈现给 View 的 ViewModel 显示数据的视图 当然 某些模型可以重用并显示在多个视图中 在我的例子中 数
  • ChangeDetectionStrategy.OnPush 的行为不符合我的预期

    我正在尝试熟悉 Angular 2ChangeDetectionStrategy OnPush性能提升 如所解释的here https blog thoughtram io angular 2016 02 22 angular 2 chan