我正在尝试用Angular2 final完全理解变化检测.
这包括:
我以为我已经对这些概念进行了非常明确的概述,但为了确保我的假设正确,我写了一个小傻瓜来测试它们.
我对全球正确的一般理解,但在某些情况下,我有点迷失.
这是plunker:Angular2变化检测操场
对plunker的快速解释:
很简单:
parent属性可以通过以下任一方式传递给子组件:
对于每个子组件,可以附加或分离ChangeDetector.("detach()"和"reattach()"按钮)
OnPush子项具有可以编辑的附加内部属性,并且可以显式应用更改检测("detectChanges()"按钮)
以下是我得到无法解释的行为的场景:
Scenario1:
预期的行为: 我希望两个孩子都不会被更新,因为他们都有自己的变化探测器.
当前行为: 默认子项未更新,但OnPush子项已更新.. 为什么? 它不应该因为它的CD分离...
Scenario2:
预期的行为: OnPush的孩子不应该全部更新,再次因为它的CD被分离...... CD不应该在这个组件上发生
当前行为: 更新值和内部值,将完整CD等接缝应用于此组件.
预期行为: 不应更新内部值,因为CD仍然已分离
当前行为: …
获得更改检测错误
检查后表情发生了变化.上一个值:'true'.当前价值:'假'
所以我想手动运行另一轮变化检测.找到有关使用ApplicationRef.tick()但当前收到错误的信息
ERROR在[默认] C:\ development\SolarUI11\src\app\update\update.component.ts:8:11类型'{selector:string; 风格:任何[]; 模板:任何; 提供者:( typeof ApplicationRef | typeof Date ...'不能分配给'Component'类型的参数.属性'provider'的类型是不兼容的.Type'(typeof ApplicationRef | typeof DatePipe)[]'不能赋值给' Provider []'.类型'typeof ApplicationRef | typeof DatePipe'不能分配给'Provider'类型.类型'typeof ApplicationRef'不能分配给'Provider'类型.类型'typeof ApplicationRef'不能分配给'FactoryProvide r'类型类型'typeof ApplicationRef'中缺少属性'provide'
我想我只是坚持实现这个的语法,自己找不到足够的信息才能使用它.
打字稿:
import { Component, Input, ApplicationRef } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
import {DatePipe} from "@angular/common";
import { DataTable } from '../data/datatable';
import { DPS } from '../data/datainfo.ts';
@Component({
selector: 'update-validation',
styleUrls: ['../app.component.css'],
templateUrl: 'update.component.html',
providers: [DatePipe, ApplicationRef]
}) …Run Code Online (Sandbox Code Playgroud) 我的角度4应用程序中有一个类(界面),它有很多字段.请注意,此类/接口的实例是immutable(即不会更改成员).
例如
public interface IHaveALotOfFields {
field1: string;
//...
field500: string;
}
Run Code Online (Sandbox Code Playgroud)
此接口通过(单例/应用程序级别提供)服务提供,该服务将类作为成员公开.例如
@Injectable()
public class MyService {
public translations: ITranslationsProvider;
}
Run Code Online (Sandbox Code Playgroud)
该服务被注入许多组件(几乎所有组件),并且经常在其相应的模板中使用,并且通常也在ts组件的部分中使用.例如
@Component({
template: `Value: {{service.field500}}`
})
export class MyComponent {
public constructor(public service: MyService) {
}
private doSomething(): string {
return this.service.field1;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题:
ChangeDetectionStrategy.OnPush,但不是为每个组件指定这个,可以在类本身或服务的成员上声明)请注意,我不想将所有组件的更改检测策略更改为OnPush.
我正在开发一个Angular 4应用程序,但我遇到了一个问题,因为我不得不this.changeDetectorRef.detectChanges();在模型更改时调用更新视图.例如,我有这个用于分页的代码:
changePage(pageNumber) {
this.currentPage = pageNumber;
// why do I need to do this?
this.changeDetectorRef.detectChanges();
}
Run Code Online (Sandbox Code Playgroud)
我已经明确地在组件上设置了更改检测策略,ChangeDetectionStrategy.Default但这没有任何效果.在订阅一个observable时也会发生这种情况:
showResults(preference) {
this.apiService.get('dining_autocomplete/', `?search=${preference}`)
.subscribe((results) => {
this.searchResults = results;
// why do I need to do this?
this.changeDetectorRef.detectChanges();
});
}
Run Code Online (Sandbox Code Playgroud)
如果我console.log() this.searchResults在TypeScript中,我得到了预期的结果,但是如果我{{ searchResults }}在HTML中使用它,它就不会更新,直到其他事件发生,大概是当它经历另一个摘要周期时.
会发生什么事?
==编辑=============================================== ============
我的组件的代码如下所示:
import {ChangeDetectorRef, Component, Input, OnChanges} from "@angular/core";
import * as _ from 'lodash';
@Component({
selector: 'dining-search-results',
templateUrl: './dining-search-results.template.html',
styleUrls: ['./dining-search-results.style.scss'],
})
export class DiningSearchResultsComponent { …Run Code Online (Sandbox Code Playgroud) 我理解变量检测在Angular 5.0中是如何工作的.
有人可以帮助我理解React中的相同功能以及它与Angular的不同之处是什么?
本文提到
常春藤为未来打开了一些可能性。现在应该可以在没有zone.js的情况下运行应用程序,并以半手动方式处理变更检测(有点像使用React一样)。这些API已经存在,但只是实验性的,没有记录在案,并且可能会在不久的将来发生变化。
我认为已经可以在Ivy之前运行没有zone.js的应用程序了。常春藤是否允许半手动处理变更检测?这些实验性API在哪里?有文件吗?常春藤仍然使用zone.js吗?
我的目标是通过手动触发更改检测来将更改检测降至最低。这样做的最佳选择是什么。特别是使用常春藤时最好的选择是什么。
我有下一个根组件模板,它绘制了9个tile:
<ul>
<li *ngFor="let x of [0,1,2,3,4,5,6,7,8]">
<tile></tile>
</li>
</ul>
Run Code Online (Sandbox Code Playgroud)
和下一个tile组件,我在其中添加了HostListener以进行文档点击:
import {AfterViewChecked, Component, HostListener} from '@angular/core';
@Component({
selector: 'tile',
template: '<p>tile works!</p>'
})
export class TileComponent implements AfterViewChecked {
ngAfterViewChecked(): void {
console.log('checked');
}
@HostListener('document:click', ['$event'])
onOutsideClick(event: any): void {
// do nothing ...
}
}
Run Code Online (Sandbox Code Playgroud)
Plunker:http://plnkr.co/edit/7wvon25LhXkHQiMcwh48?p =preview
我不明白为什么.
有人可以向我解释为什么在这种情况下变化检测触发n ^ 2次?
我有这个管道,它将输入值乘以从服务检索到的其他值:
@Pipe({
name: 'multiply'
})
export class MultiplyPipe implements PipeTransform {
constructor(private service: StateService) { }
transform(value: any, args?: any): any {
return value * this.service.multiplier;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
{{ value | multiply }}
Run Code Online (Sandbox Code Playgroud)
这工作正常,但是当multiply服务的值发生更改时,它不会触发任何更改检测,因此
{{ value | multiply }}
Run Code Online (Sandbox Code Playgroud)
不再运行,将旧值保留在屏幕上.有什么建议可以修复吗?
我知道如果我在模板中使用方法调用,它会一遍又一遍地执行(不理想)。我已经通过使用纯管道和记忆方法的组合解决了这个问题。但我也在使用反应式表单,并在我的模板中使用 myFormGroup.get('myFormControl').value 来获取值。这是否也会像我的组件中的方法一样重复执行,或者 Angular 是否有适当的策略来防止这种情况发生?一个用法示例是使用 *ngIf 并让条件基于表单的值。
此外,我目前没有遇到任何性能下降,但我想在使用此应用程序走得太远之前以最佳方式实现这一点(并且只是好奇)。
我可以轻松地更新它以直接引用表单对象上的属性,我只是更喜欢方法调用的语法。任何见解都会有所帮助,谢谢!
我复制了一个简单的stackblitz,演示了我遇到的问题。问题是我有一个父组件将布尔值传递给子组件。这个布尔值是子组件上的@Input。需要注意的是,父组件使用ChangeDetectionStrategy.OnPush。子组件没有显式设置。
当父组件在订阅方法中更改子组件的布尔输入属性时,子组件最初不会检测到更改。总是需要单击 2 次才能让子组件检测到更改。
但是,当我在订阅方法之外更改子组件的布尔输入属性时,子组件会正确检测到更改,并且一切都会按预期工作(单击 1 次子组件即可识别更改)。
App.Component.ts(父组件)
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
constructor(private http: HttpClient) {
}
public isHelloVisible: boolean;
public useHttpGet: boolean;
showHello() {
if (this.useHttpGet) {
this.http.get('https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/cc0e3799790b0b34bdeb6fef28c3daf7/17.447409200000003,-78.3724573?units=si').subscribe(data => {
this.isHelloVisible = true;
});
} else {
this.isHelloVisible = true;
}
}
closeHello() {
this.isHelloVisible = false;
}
Run Code Online (Sandbox Code Playgroud)
子组件(Hello.component.ts)
@Component({
selector: 'hello',
template: `<div *ngIf="showHello">
Hello
<div (click)="closeHello()">Click me to close Hello</div>
</div>
`, …Run Code Online (Sandbox Code Playgroud) angular ×10
typescript ×2
angular-ivy ×1
javascript ×1
observable ×1
plunker ×1
reactjs ×1
virtual-dom ×1
zone ×1