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
|
||||
*/
|
||||
|
||||
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> {
|
||||
constructor(
|
||||
|
@ -93,8 +93,12 @@ export class NgForOfContext<T> {
|
|||
*
|
||||
*/
|
||||
@Directive({selector: '[ngFor][ngForOf]'})
|
||||
export class NgForOf<T> implements DoCheck, OnChanges {
|
||||
@Input() ngForOf: NgIterable<T>;
|
||||
export class NgForOf<T> implements DoCheck {
|
||||
@Input()
|
||||
set ngForOf(ngForOf: NgIterable<T>) {
|
||||
this._ngForOf = ngForOf;
|
||||
this._ngForOfDirty = true;
|
||||
}
|
||||
@Input()
|
||||
set ngForTrackBy(fn: TrackByFunction<T>) {
|
||||
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; }
|
||||
|
||||
private _ngForOf: NgIterable<T>;
|
||||
private _ngForOfDirty: boolean = true;
|
||||
private _differ: IterableDiffer<T>|null = null;
|
||||
private _trackByFn: TrackByFunction<T>;
|
||||
|
||||
|
@ -127,10 +133,11 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
|||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if ('ngForOf' in changes) {
|
||||
ngDoCheck(): void {
|
||||
if (this._ngForOfDirty) {
|
||||
this._ngForOfDirty = false;
|
||||
// React on ngForOf changes only once all inputs have been initialized
|
||||
const value = changes['ngForOf'].currentValue;
|
||||
const value = this._ngForOf;
|
||||
if (!this._differ && value) {
|
||||
try {
|
||||
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) {
|
||||
const changes = this._differ.diff(this.ngForOf);
|
||||
const changes = this._differ.diff(this._ngForOf);
|
||||
if (changes) this._applyChanges(changes);
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +159,7 @@ export class NgForOf<T> implements DoCheck, OnChanges {
|
|||
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
|
||||
if (item.previousIndex == null) {
|
||||
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);
|
||||
insertTuples.push(tuple);
|
||||
} else if (currentIndex == null) {
|
||||
|
|
|
@ -59,27 +59,18 @@
|
|||
{
|
||||
"name": "NgIfContext"
|
||||
},
|
||||
{
|
||||
"name": "NgOnChangesFeature"
|
||||
},
|
||||
{
|
||||
"name": "Optional"
|
||||
},
|
||||
{
|
||||
"name": "PARAMETERS"
|
||||
},
|
||||
{
|
||||
"name": "PRIVATE_PREFIX"
|
||||
},
|
||||
{
|
||||
"name": "ROOT_DIRECTIVE_INDICES"
|
||||
},
|
||||
{
|
||||
"name": "RecordViewTuple"
|
||||
},
|
||||
{
|
||||
"name": "SimpleChange"
|
||||
},
|
||||
{
|
||||
"name": "SkipSelf"
|
||||
},
|
||||
|
|
|
@ -160,11 +160,6 @@ if (!(NgIf as any).ngDirectiveDef) {
|
|||
selectors: [['', 'ngFor', '', 'ngForOf', '']],
|
||||
factory: () => new NgForOf(
|
||||
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
||||
features: [NgOnChangesFeature({
|
||||
ngForOf: 'ngForOf',
|
||||
ngForTrackBy: 'ngForTrackBy',
|
||||
ngForTemplate: 'ngForTemplate',
|
||||
})],
|
||||
inputs: {
|
||||
ngForOf: 'ngForOf',
|
||||
ngForTrackBy: 'ngForTrackBy',
|
||||
|
|
|
@ -20,7 +20,6 @@ NgForOf.ngDirectiveDef = defineDirective({
|
|||
selectors: [['', 'ngForOf', '']],
|
||||
factory: () => new NgForOfDef(
|
||||
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
|
||||
features: [NgOnChangesFeature()],
|
||||
inputs: {
|
||||
ngForOf: 'ngForOf',
|
||||
ngForTrackBy: 'ngForTrackBy',
|
||||
|
|
|
@ -240,13 +240,12 @@ export declare class NgComponentOutlet implements OnChanges, OnDestroy {
|
|||
ngOnDestroy(): void;
|
||||
}
|
||||
|
||||
export declare class NgForOf<T> implements DoCheck, OnChanges {
|
||||
export declare class NgForOf<T> implements DoCheck {
|
||||
ngForOf: NgIterable<T>;
|
||||
ngForTemplate: TemplateRef<NgForOfContext<T>>;
|
||||
ngForTrackBy: TrackByFunction<T>;
|
||||
constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForOfContext<T>>, _differs: IterableDiffers);
|
||||
ngDoCheck(): void;
|
||||
ngOnChanges(changes: SimpleChanges): void;
|
||||
}
|
||||
|
||||
export declare class NgForOfContext<T> {
|
||||
|
|
Loading…
Reference in New Issue