refactor(common): Remove ngOnChanges from NgForOf (#23378)
`NgForOf` used to implement `OnChanges` and than use `ngOnChanges` callback to detect when `ngForOf` binding changed to update the differ. We now do the checking manually which puts less pressure on the runtime to do the bookkeeping and should result in minor perf improvement. PR Close #23378
This commit is contained in:
parent
255463ed48
commit
08a18b82de
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, OnChanges, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, forwardRef, isDevMode} from '@angular/core';
|
import {ChangeDetectorRef, Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, forwardRef, isDevMode} from '@angular/core';
|
||||||
|
|
||||||
export class NgForOfContext<T> {
|
export class NgForOfContext<T> {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -93,8 +93,12 @@ export class NgForOfContext<T> {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Directive({selector: '[ngFor][ngForOf]'})
|
@Directive({selector: '[ngFor][ngForOf]'})
|
||||||
export class NgForOf<T> implements DoCheck, OnChanges {
|
export class NgForOf<T> implements DoCheck {
|
||||||
@Input() ngForOf: NgIterable<T>;
|
@Input()
|
||||||
|
set ngForOf(ngForOf: NgIterable<T>) {
|
||||||
|
this._ngForOf = ngForOf;
|
||||||
|
this._ngForOfDirty = true;
|
||||||
|
}
|
||||||
@Input()
|
@Input()
|
||||||
set ngForTrackBy(fn: TrackByFunction<T>) {
|
set ngForTrackBy(fn: TrackByFunction<T>) {
|
||||||
if (isDevMode() && fn != null && typeof fn !== 'function') {
|
if (isDevMode() && fn != null && typeof fn !== 'function') {
|
||||||
|
@ -110,6 +114,8 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
||||||
|
|
||||||
get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; }
|
get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; }
|
||||||
|
|
||||||
|
private _ngForOf: NgIterable<T>;
|
||||||
|
private _ngForOfDirty: boolean = true;
|
||||||
private _differ: IterableDiffer<T>|null = null;
|
private _differ: IterableDiffer<T>|null = null;
|
||||||
private _trackByFn: TrackByFunction<T>;
|
private _trackByFn: TrackByFunction<T>;
|
||||||
|
|
||||||
|
@ -127,10 +133,11 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngDoCheck(): void {
|
||||||
if ('ngForOf' in changes) {
|
if (this._ngForOfDirty) {
|
||||||
|
this._ngForOfDirty = false;
|
||||||
// React on ngForOf changes only once all inputs have been initialized
|
// React on ngForOf changes only once all inputs have been initialized
|
||||||
const value = changes['ngForOf'].currentValue;
|
const value = this._ngForOf;
|
||||||
if (!this._differ && value) {
|
if (!this._differ && value) {
|
||||||
try {
|
try {
|
||||||
this._differ = this._differs.find(value).create(this.ngForTrackBy);
|
this._differ = this._differs.find(value).create(this.ngForTrackBy);
|
||||||
|
@ -140,11 +147,8 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ngDoCheck(): void {
|
|
||||||
if (this._differ) {
|
if (this._differ) {
|
||||||
const changes = this._differ.diff(this.ngForOf);
|
const changes = this._differ.diff(this._ngForOf);
|
||||||
if (changes) this._applyChanges(changes);
|
if (changes) this._applyChanges(changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +159,7 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
||||||
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
|
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
|
||||||
if (item.previousIndex == null) {
|
if (item.previousIndex == null) {
|
||||||
const view = this._viewContainer.createEmbeddedView(
|
const view = this._viewContainer.createEmbeddedView(
|
||||||
this._template, new NgForOfContext<T>(null !, this.ngForOf, -1, -1), currentIndex);
|
this._template, new NgForOfContext<T>(null !, this._ngForOf, -1, -1), currentIndex);
|
||||||
const tuple = new RecordViewTuple<T>(item, view);
|
const tuple = new RecordViewTuple<T>(item, view);
|
||||||
insertTuples.push(tuple);
|
insertTuples.push(tuple);
|
||||||
} else if (currentIndex == null) {
|
} else if (currentIndex == null) {
|
||||||
|
|
|
@ -59,27 +59,18 @@
|
||||||
{
|
{
|
||||||
"name": "NgIfContext"
|
"name": "NgIfContext"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "NgOnChangesFeature"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Optional"
|
"name": "Optional"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "PARAMETERS"
|
"name": "PARAMETERS"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "PRIVATE_PREFIX"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "ROOT_DIRECTIVE_INDICES"
|
"name": "ROOT_DIRECTIVE_INDICES"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "RecordViewTuple"
|
"name": "RecordViewTuple"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "SimpleChange"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "SkipSelf"
|
"name": "SkipSelf"
|
||||||
},
|
},
|
||||||
|
|
|
@ -160,11 +160,6 @@ if (!(NgIf as any).ngDirectiveDef) {
|
||||||
selectors: [['', 'ngFor', '', 'ngForOf', '']],
|
selectors: [['', 'ngFor', '', 'ngForOf', '']],
|
||||||
factory: () => new NgForOf(
|
factory: () => new NgForOf(
|
||||||
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
||||||
features: [NgOnChangesFeature({
|
|
||||||
ngForOf: 'ngForOf',
|
|
||||||
ngForTrackBy: 'ngForTrackBy',
|
|
||||||
ngForTemplate: 'ngForTemplate',
|
|
||||||
})],
|
|
||||||
inputs: {
|
inputs: {
|
||||||
ngForOf: 'ngForOf',
|
ngForOf: 'ngForOf',
|
||||||
ngForTrackBy: 'ngForTrackBy',
|
ngForTrackBy: 'ngForTrackBy',
|
||||||
|
|
|
@ -20,7 +20,6 @@ NgForOf.ngDirectiveDef = defineDirective({
|
||||||
selectors: [['', 'ngForOf', '']],
|
selectors: [['', 'ngForOf', '']],
|
||||||
factory: () => new NgForOfDef(
|
factory: () => new NgForOfDef(
|
||||||
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
||||||
features: [NgOnChangesFeature()],
|
|
||||||
inputs: {
|
inputs: {
|
||||||
ngForOf: 'ngForOf',
|
ngForOf: 'ngForOf',
|
||||||
ngForTrackBy: 'ngForTrackBy',
|
ngForTrackBy: 'ngForTrackBy',
|
||||||
|
|
|
@ -240,13 +240,12 @@ export declare class NgComponentOutlet implements OnChanges, OnDestroy {
|
||||||
ngOnDestroy(): void;
|
ngOnDestroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class NgForOf<T> implements DoCheck, OnChanges {
|
export declare class NgForOf<T> implements DoCheck {
|
||||||
ngForOf: NgIterable<T>;
|
ngForOf: NgIterable<T>;
|
||||||
ngForTemplate: TemplateRef<NgForOfContext<T>>;
|
ngForTemplate: TemplateRef<NgForOfContext<T>>;
|
||||||
ngForTrackBy: TrackByFunction<T>;
|
ngForTrackBy: TrackByFunction<T>;
|
||||||
constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForOfContext<T>>, _differs: IterableDiffers);
|
constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForOfContext<T>>, _differs: IterableDiffers);
|
||||||
ngDoCheck(): void;
|
ngDoCheck(): void;
|
||||||
ngOnChanges(changes: SimpleChanges): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class NgForOfContext<T> {
|
export declare class NgForOfContext<T> {
|
||||||
|
|
Loading…
Reference in New Issue