Angular OnPush Component 주의해야 할 곳: 계속
5665 단어 Angular
componentRef.changeDetectorRef.detectChanges()
is confusing. @component({
selector: 'dynamic',
template: `{{name}}`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class Dynamic {
name = 'initial name';
}
@component({
selector: 'my-app',
template: `
<b>Expected</b>: "initial name" changes to "changed name" after 2s<br>
<b>Actual</b>:<br>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
constructor(private _vcRef: ViewContainerRef,
private _cfr: ComponentFactoryResolver, private _injector: Injector) {}
ngOnInit() {
const cmptRef = this._cfr.resolveComponentFactory(Dynamic).create(this._injector);
this._vcRef.insert(cmptRef.hostView);
setTimeout(() => {
cmptRef.instance.name = 'changed name';
cmptRef.changeDetectorRef.detectChanges(); // this will not update the DOM.
// cmptRef.injector.get(ChangeDetectorRef).detectChanges(); // this will update the DOM.
}, 2000);
}
}
이 케이스가
Dynamic
의 OnPush Component 를 추가해, 이 component의 cmptRef.changeDetectorRef.detectChanges()
를 호출해도, 화면이 갱신되지 않는다고 하는 현상이 됩니다.그리고
cmptRef.injector.get(ChangeDetectorRef).detectChanges();
에서 실행되면 화면이 업데이트되었습니다.그 원인이
cmptRef.changeDetectorRef
가 이 OnPush Component 의 changeDetectorRef 가 아니고, 그 Component 를 포함하는 Placeholder 의 HostView 의 changeDetectorRef 가 됩니다.그래서이 HostView의
detectChanges()
를 호출하여 OnPush Component가 아직 Dirty가 아니기 때문에 화면이 업데이트되지 않습니다.ComponentFixture.detectChanges()
is confusing const myComp = TestBed.createComponent(OnPushComponent);
myComp.componentInstance.abc = 123;
myComp.detectChanges() // Does not work
myComp.componentRef.injector.get(ChangeDetectorRef).detectChanges(); // This will work.
케이스 1과 비슷하지만 테스트에도 이 현상이 있습니다.
ngDoCheck()
가 실행되었지만 실제로 ChangeDetection
가 실행되지 않았습니다. @Component({
selector: "onpush",
template: `
onpush: {{ name }} <br />
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPush implements DoCheck {
name = "initial name";
ngDoCheck() {
console.log("docheck onpush");
}
}
@Component({
selector: "my-app",
template: `
<onpush></onpush>
<button (click)="onClick()">Update onpush</button>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
@ViewChild(OnPush) onPushComp: OnPush;
constructor() {}
onClick() {
this.onPushComp.name = 'new name';
}
}
이 경우 OnPush가 업데이트되지 않는 것은 정확하지만
ngDoCheck
가 실행 된 것이 이상합니다.그 이유는
HostView
의 존재입니다. 실제로는 Component의 Lifecycle hooks가 부모의 View에 속하기 때문입니다.dev mode
에서 OnPush Component가 CheckNoChanges()
가 실행되고 있지 않습니다, 즉 어떤 패턴이라도 ExpressionChangedAfterItHasBeenCheckedError
이 될 수 없습니다. import {
Component,
NgModule,
ViewChild,
ChangeDetectionStrategy,
DoCheck,
Input, AfterViewInit
} from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
@Component({
selector: "onpush",
template: `
onpush: {{ name }} <br />
{{ input }}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPush implements AfterViewInit {
name = 'initial name';
ngAfterViewInit() {
this.name = 'updated name';
}
}
@Component({
selector: "my-app",
template: `
<b>Expected</b>: "initial name" changes to "new name" after button click<br />
<b>Actual</b>:<br />
<onpush></onpush>
`,
changeDetection: ChangeDetectionStrategy.Default
})
export class AppComponent {
@ViewChild(OnPush) onPushComp: OnPush;
constructor() {}
}
그 원인이 지금 Angular가
ExpressionChangedAfterItHasBeenCheckedError
를 탐지하기 위해 개발 모드에서 두 번 Change Detection을 실행했습니다. OnPush의 경우, 1회째로 Dirty 플래그를 리셋트 해, 2회째가 Dirty가 아닌 상태가 되어, CheckNoChanges의 처리가 실행되지 않게 되었습니다.그렇다면 왜
HostView
라는 개념이 있습니까? 조금 다양한 레거시의 원인이 있습니다.라는 것이 되었습니다.
이 HostView가 개발자 의식하고 싶지 않은 것이므로, 개발자가 직접 접촉하는 케이스가 없을 것입니다만, 상기의 케이스로 조금 이해하기 어려운 것이 발생했습니다.
이제 이러한 문제를 해결하기 위해 상당히 Change Detection의 데이터 구조 로직을 업데이트하는 것이 어려워 지금부터
그렇게 됩니다.
지금 내 쪽에서 1번째를 대응중입니다만, 여러분이 이러한 문제를 맞을 때, 이 기사가 참고가 되면 좋다고 생각합니다.
이상입니다, 정말 고마워요.
Reference
이 문제에 관하여(Angular OnPush Component 주의해야 할 곳: 계속), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Jialipassion/items/da2401a242e7ba2794d6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)