如何在 Angular 中使用变更检测策略

简介

默认情况下,Angular 2+ 会在应用程序中的每次变化时对所有组件(从上到下)执行变更检测。变化可以来自用户事件或者从网络请求接收到的数据。

变更检测非常高效,但随着应用程序变得更加复杂并且组件数量增加,变更检测将不得不执行越来越多的工作。

其中一个解决方案是为特定组件使用 OnPush 变更检测策略。这将指示 Angular 仅在向这些组件及其子树传递新引用时才运行变更检测,而不是在数据发生变化时运行变更检测。

在本文中,您将学习关于 ChangeDetectionStrategyChangeDetectorRef

先决条件

如果您想跟随本文,您需要:

  • 一些熟悉 Angular 组件可能会有所帮助。
  • 本文还涉及 RxJS 库,熟悉 BehaviorSubjectObservable 也可能会有所帮助。

探索 ChangeDetectionStrategy 示例

让我们来看一个带有子组件的示例组件,该子组件显示水生生物列表,并允许用户向列表中添加新的生物:

import { Component } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html'
})
export class AppComponent {aquaticCreatures = ['shark', 'dolphin', 'octopus'];addAquaticCreature(newAquaticCreature) {this.aquaticCreatures.push(newAquaticCreature);}
}

模板如下:

<input #inputAquaticCreature type="text" placeholder="Enter a new creature">
<button (click)="addAquaticCreature(inputAquaticCreature.value)">Add creature</button><app-child [data]="aquaticCreatures"></app-child>

app-child 组件如下:

import { Component, Input } from '@angular/core';@Component({selector: 'app-child',templateUrl: './child.component.html'
})
export class ChildComponent {@Input() data: string[];
}

app-child 模板如下:

<ul><li *ngFor="let item of data">{{ item }}</li>
</ul>

编译并在浏览器中访问应用程序后,您应该看到一个无序列表,其中包含 sharkdolphinoctopus

在输入框中输入水生生物名称,然后单击 Add creature 按钮将新生物添加到列表中。

当 Angular 检测到父组件中的数据发生变化时,子组件将会更新。

现在,让我们将子组件的变更检测策略设置为 OnPush

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';@Component({selector: 'app-child',templateUrl: './child.component.html',changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {@Input() data: string[];
}

重新编译并在浏览器中访问应用程序后,您应该看到一个无序列表,其中包含 sharkdolphinoctopus

然而,添加新的水生生物似乎不会将其追加到无序列表中。新数据仍然被推送到父组件的 aquaticCreatures 数组中,但 Angular 并未识别到数据输入的新引用,因此它不会对组件运行变更检测。

要向数据输入传递新引用,您可以在 addAquaticCreature 中使用 spread syntax (...) 替换 Array.push

// ...
addAquaticCreature(newAquaticCreature) {this.aquaticCreatures = [...this.aquaticCreatures, newAquaticCreature];
}
// ...

使用这种变化后,您不再对 aquaticCreatures 数组进行突变。您将返回一个全新的数组。

重新编译后,您应该观察到应用程序的行为与之前相同。Angular 检测到了对 data 的新引用,因此它对子组件运行了变更检测。

这就完成了修改示例父子组件以使用 OnPush 变更检测策略。

探索 ChangeDetectorRef 示例

在使用 OnPush 变更检测策略时,除了确保每次应该发生变化时都传递新引用之外,您还可以利用 ChangeDetectorRef 来完全控制。

ChangeDetectorRef.detectChanges()

例如,您可以继续对数据进行突变,然后在子组件中添加一个带有 Refresh 按钮的按钮。

这将需要将 addAquaticCreature 恢复为使用 Array.push

// ...
addAquaticCreature(newAquaticCreature) {this.aquaticCreatures.push(newAquaticCreature);
}
// ...

并添加一个触发 refresh()button 元素:

<ul><li *ngFor="let item of data">{{ item }}</li>
</ul><button (click)="refresh()">Refresh</button>

然后,修改子组件以使用 ChangeDetectorRef

import {Component,Input,ChangeDetectionStrategy,ChangeDetectorRef
} from '@angular/core';@Component({selector: 'app-child',templateUrl: './child.component.html',changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {@Input() data: string[];constructor(private cd: ChangeDetectorRef) {}refresh() {this.cd.detectChanges();}
}

重新编译并在浏览器中访问应用程序后,您应该看到一个无序列表,其中包含 sharkdolphinoctopus

向数组添加新项不会更新无序列表。但是,单击 Refresh 按钮将会对组件运行变更检测,并进行更新。

ChangeDetectorRef.markForCheck()

假设你的数据输入实际上是一个 observable。

这个例子将使用 RxJS 的 BehaviorSubject

import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';@Component({ selector: 'app-root',templateUrl: './app.component.html'
})
export class AppComponent {aquaticCreatures = new BehaviorSubject(['shark', 'dolphin', 'octopus']);addAcquaticCreature((newAquaticCreature) {this.aquaticCreatures.next(newAquaticCreature);}
}

并且你在子组件的 OnInit 钩子中订阅它。

你将在这里将水生生物添加到 aquaticCreatures 数组中:

import {Component,Input,ChangeDetectionStrategy,ChangeDetectorRef,OnInit
} from '@angular/core';
import { Observable } from 'rxjs';@Component({selector: 'app-child',templateUrl: './child.component.html',changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {@Input() data: Observable<any>;aquaticCreatures: string[] = [];constructor(private cd: ChangeDetectorRef) {}ngOnInit() {this.data.subscribe(newAquaticCreature => {this.aquaticCreatures = [...this.aquaticCreatures, ...newAquaticCreature];});}
}

这段代码不完整,因为新数据会改变 data observable,所以 Angular 不会运行变更检测。解决方案是在订阅 observable 时调用 ChangeDetectorRefmarkForCheck

// ...
ngOnInit() {this.data.subscribe(newAquaticCreature => {this.aquaticCreatures = [...this.aquaticCreatures, ...newAquaticCreature];this.cd.markForCheck();});
}
// ...

markForCheck 指示 Angular 当特定输入发生变化时应触发变更检测。

ChangeDetectorRef.detach()ChangeDetectorRef.reattach()

使用 ChangeDetectorRef 还可以完全手动分离和重新附加变更检测,通过 detachreattach 方法。

结论

在本文中,你了解了 ChangeDetectionStrategyChangeDetectorRef。默认情况下,Angular 将对所有组件执行变更检测。ChangeDetectionStrategyChangeDetectorRef 可以应用于组件,以在新引用与数据发生变化时执行变更检测。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/682635.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对(一维)数组与指针的深入理解(1)

目录 1.数组名的理解2.使用指针访问&#xff08;一维&#xff09;数组3.&#xff08;一维&#xff09;数组传参的本质 1.数组名的理解 以前我们在使用指针访问数组内容时&#xff0c;有这样的代码&#xff1a; #include <stdio.h>int main() {int arr[10] { 1,2,3,4,5…

详解Qt多线程(包含:什么是CPU,单核处理器和多核处理器,举餐厅和QQ音乐的例子详解进程和线程,Qt多线程案例)

目录 一.什么是CPU&#xff1f;二.单核处理器与多核处理器三.什么是进程和线程&#xff1f;3.1 定义3.2 以餐厅为例子解释进程和线程3.2 以QQ音乐为例子&#xff0c;解释QQ音乐里面的进程和线程 四.Qt中的多线程五.Qt多线程案例任务描述案例演示设置显示内容的字体大小和位置运…

pands常用操作

1.导入库和文件读取和文件分信息分析 import pandas as pd import numpy as np csvf pd.read_csv(D:/各个站程序版本说明.csv) csvf.info() <class pandas.core.frame.DataFrame> RangeIndex: 51 entries, 0 to 50 Data columns (total 6 columns):# Column Non-Nul…

java面试题整理

2023.2.14&#xff08;第二天&#xff09; 数组是不是对象&#xff1f; 在Java中&#xff0c;数组是对象。数组是一种引用类型&#xff0c;它可以存储固定大小的相同类型的元素序列。在Java中&#xff0c;数组是通过new关键字创建的&#xff0c;它们在内存中被分配为对象&…

Java 中 Hashtable和ConcurrentHashMap的区别

Hashtable和ConcurrentHashMap的区别 Hashtable 和 ConcurrentHashMap 都是 Java 中的集合框架中的 Map 接口实现类&#xff0c;但它们之间有很大的不同&#xff0c;特别是在多线程环境中。下面是它们之间的一些主要区别&#xff1a; 线程安全性&#xff1a; Hashtable 是线程…

<网络安全>《30 网络信息安全基础(1)常用术语整理》

1 肉鸡 所谓“肉鸡”是一种很形象的比喻&#xff0c;比喻那些可以随意被我们控制的电脑&#xff0c;对方可以是WINDOWS系统&#xff0c;也可以是UNIX/LINUX系统&#xff0c;可以是普通的个人电脑&#xff0c;也可以是大型的服务器&#xff0c;我们可以象操作自己的电脑那样来操…

网络世界的基石:深入探索OSI 7层模型的奥秘

引言 在当今互联网和计算机网络的复杂体系中&#xff0c;OSI&#xff08;开放系统互连&#xff09;参考模型提供了一个理解和设计网络通信协议的框架。自1984年由国际标准化组织&#xff08;ISO&#xff09;提出以来&#xff0c;OSI 7层模型已成为网络通信中最基本的概念之一。…

re:从0开始的CSS之旅 15. 浮动

1. 浮动 浮动&#xff1a;使元素浮起来&#xff0c;脱离文档流&#xff0c;从而使盒子能够灵活的移动。 浮动的属性&#xff1a; float 属性设置元素的浮动 可选值&#xff1a; none 元素不浮动&#xff0c;默认在文档流中排列&#xff08;默认值&#xff09; left 元素向左移…

「数据结构」MapSet

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; Map&Set &#x1f349;概念&#x1f349;模型&#x1f349;Map&#x1f34c;TreeMap和HashMap的区别&#x1f34c;Map常用方…

2048游戏C++板来啦!

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 大家好呀&#xff0c;我是PingdiGuo_guo&#xff0c;今天我们来学习如何用C编写一个2048小游戏。 文章目录 1.2048的规则 2.步骤实现 2.1: 初始化游戏界面 2.1.1知识点 2.1.2: 创建游戏界面 2.2: 随机…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第二天-ARM按键1*3矩阵键盘编程 (物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1E4x2TX_9SYhxM9sWfnehMg?pwd1688 提取码&#xff1a;1688 1、键盘1*3的中断程序 //************************************************ #include "2440addr.h" #include "2440lib.h" #include &…

Days 31 ElfBoard 自启脚本中打开看门狗

1.在开机自启脚本中打开看门狗 rootELF1:~# vi /etc/rc.local 2.在自启脚本中添加上之后&#xff0c;然后在咱们的QT界面中找到看门狗应用&#xff0c; 发现显示打开看门狗失败&#xff1a; 3.修改看门狗源码&#xff0c;设置了超时时间后&#xff0c;关闭/dev/dev/watchdog节…

【Tomcat】:One or more listeners failed to start.报错解决方案

报错信息:One or more listeners failed to start. Full details will be found in the appropriate container log file. 具体就是web.xml此配置报错: 服务器启动错误Tomcat:One or more listeners failed to start.报错解决方案 IDEA:在使用IDEA运行SSM项目的时候 , Tomcat运…

.NET Core性能优化技巧

.NET Core作为一个跨平台的开源框架&#xff0c;以其高效、灵活和可扩展的特性受到了广大开发者的青睐。但在实际开发中&#xff0c;如何确保应用程序的性能始终是一个关键的问题。本文将介绍十大.NET Core性能优化技巧&#xff0c;帮助开发者提升应用程序的性能。 1. 使用异步…

error MSB8008: 指定的平台工具集(v143)未安装或无效。请确保选择受支持的 PlatformToolset 值解决办法

右击解决方案&#xff0c;选择属性 将工具集为143的修改为其他&#xff0c;如图 重新编译即可运行

网络原理(3)--以太网协议,DNS

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;网络原理(3)–以太网协议,DNS 在网络原理(2)中介绍了网络层中的一个重要的协议–ip协议,网络层关注的通信时的起点和终点,而数据链路层更加"底层"一些,关注的是传输过程…

关于TypeError:无法读取null属性(读取‘isCE‘) -自定义组件库

关于TypeError:无法读取null属性(读取’isCE’) -自定义组件库 大家先看一下这个文章 https://cloud.tencent.com/developer/ask/sof/106913760 这个文章里面给了vite解决方案 这里我给出一个webpack解决方案 首先我建议你的组件库和你的项目进行vue版本锁定 第二补在你的vue.c…

假期作业 11

整理chmod、chgrp、chown指令的应用成文档 chmod 文件分类: bcd-lsp d 目录 - 普通文件 b 块设备驱动文件 磁盘 c 字符设备驱动文件 键盘 鼠标 l link 链接文件 软连接 硬连接 网络编程 s socket 套接字文件 网络编程 p pipe 管道文件 权限内容 r read w write - 无…

【Effective Objective - C 2.0】——读书笔记(四)

文章目录 二十三、通过委托与数据源协议进行对象间通信二十四、将类的实现代码分散到便于管理的数个分类之中二十五、总是为第三方的分类名称加前缀二十六、切勿在分类里面声明属性二十七、使用“class-continuation分类”隐藏实现细节二十八、通过协议提供匿名对象 二十三、通…

springboot187社区养老服务平台的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…