Что произойдет, если передать на вход @Input объект при включенной стратегии OnPush
На одном из собеседований мне задали вопрос — есть компонент FooComponent, с включенной стратегией обнаружения изменения OnPush и в него передаётся объект. Что происходит в этот момент под капотом? Создает ли Angular новый объект, вынуждая FooComponent пройти проверку? Попробуем разобраться.
@Component({
template: `
<app-foo [config]="{ position: 'top' }"></app-foo>
`
})
export class AppComponent {
}@Component({
selector: 'app-foo',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FooComponent {
@Input() config: Config;
}В нашем случае, когда Angular компилирует шаблон, он замечает, что объект статический и не использует каких-либо привязок. Поэтому Angular создает его один раз, кэширует и всегда возвращает ту же ссылку при последующих проверках.
Если мы посмотрим на скомпилированный код, мы увидим, что Angular использует функцию pureFunction0, которая делает то, что мы описали выше:
const _c0 = function() {
return {
position: "top"
};
};
export class AppComponent {}
AppComponent.ɵcmp = ɵɵdefineComponent({
type: AppComponent,
template: function AppComponent_Template(rf, ctx) {
if (rf & 2) {
ɵɵproperty("config", ɵɵpureFunction0(1, _c0));
}
},
directives: [i1.FooComponent]
});Перейдем к следующему примеру, где значение одного из свойств объекта не является статическим:
@Component({
template: `
<app-foo [config]="{ position: position }"></app-foo>
`
})
export class AppComponent {
position = 'top';
change() {
this.position = 'bottom';
}
}В этом случае для Angular не важен сам объект. Когда компилятор обнаруживает привязку, он сохраняет ее значение в структуре данных LView. В коде имеется одна привязка, поэтому Angular будет использовать версию pureFunction1:
const _c0 = function() {
return {
position: "top"
};
};
export class AppComponent {}
AppComponent.ɵcmp = ɵɵdefineComponent({
type: AppComponent,
template: function AppComponent_Template(rf, ctx) {
if (rf & 2) {
ɵɵproperty("config", ɵɵpureFunction1(1, _c0, ctx.position));
}
},
directives: [i1.FooComponent]
});Эта функция вернет кэшированную ссылку на объект, если текущее значение position такое же, как и кэшированное. В противном случае она вернет новый объект, содержащий обновленное значение свойства.
Результирующий объект будет передан функции ɵɵproperty, которая использует функцию Object.is для проверки необходимости обновления свойства.
В заключение, единственным недостатком при использовании таких объектов вместо свойства компонента является то, что компилятор будет гсоздавать и выполнять дополнительный код.