Ответ 1
Люди отвечают вам, но они не объясняют вас.
Стратегия OnPush
является наиболее эффективной стратегией, когда дело доходит до обнаружения изменений. Angular не реализует его по умолчанию, потому что новички используются, чтобы увидеть магию (то есть стратегия по умолчанию более понятна и понятна, когда вы начинаете использовать Angular).
Чтобы обнаружить изменения, Angular прослушивает события в вашем представлении. При использовании стратегии по умолчанию это может привести к большому количеству бесполезного обнаружения изменений.
В стратегии push вы контролируете, когда срабатывает обнаружение изменений.
В обоих случаях Angular использует ссылки на память, чтобы знать, когда ваши данные были обновлены. Вот почему неизменность объектов так важна в Angular, а также почему реактивное программирование работает так хорошо.
При этом, если вы хотите переключиться на пуш-стратегию, вы должны использовать следующее:
// files: Uploads[] = [];
files: BehaviorSubject<Uploads[]> = new BehaviorSubject([]);
add(item) {
this.files.pipe(first()).subscribe(files => this.files.next([...files, item]));
}
get canUpload() {
// return this.files.length > 0l
return this.files.pipe(
map(files => files.length),
map(size => !!size)
);
}
get isUploading() {
// return this.files.length > 0 && this.files.some((f) => f.state === FileUpLoadState.uploading);
return this.files.pipe(
startWith(false),
filter(files => !!files.length),
filter(files => files.some(f => f.state === FileUpLoadState.uploading)),
map(() => true)
);
}
get activeFiles() {
// return this.files.filter((f) => f.state !== FileUpLoadState.success);
return this.files.pipe(
map(files => files.filter(f => f.state !== FileUpLoadState.success)),
);
}
uploadFiles() {
/*
if (!this.files.length) {
return;
}
const fileList: FileList = (event.target as HTMLInputElement).files;
for (const uploadedFile of Array.prototype.slice.call(fileList)) {
// do stuff
this.files.push(new Upload(file));
}
*/
this.files.pipe(
filter(files => !!files.length),
map(files => (event.target as HTMLInputElement).files),
first()
).subscribe(files => {
for (const uploadedFile of Array.prototype.slice.call(fileList)) {
// do stuff
this.add(new Upload(file));
}
});
}
Это одна из многих реализаций, которые вы можете сделать. Я не уверен, что это сработает так, как вы ожидаете, я просто "перевел" код, чтобы вы могли сделать одну или две корректировки.
При этом ваше представление обновляется автоматически при изменении вашей коллекции. Вам не нужно ничего делать. Это соответствует стратегии push, потому что реактивное программирование запускает обнаружение изменений.
И поскольку каждый получатель зависит от вашего BehaviorSubject, все они обновляются при каждом изменении этого предмета.
Просто "недостатком" (который на самом деле не является) является то, что в шаблоне вашего компонента вы должны использовать асинхронный канал:
<ng-container *ngIf="canUpload | async">...</ng-container>
если у вас есть вопросы, не стесняйтесь их задавать!